-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Added support functional indexes for MySQL and Postgres #6414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,7 @@ | |
use function assert; | ||
use function count; | ||
use function explode; | ||
use function get_debug_type; | ||
use function implode; | ||
use function in_array; | ||
use function is_array; | ||
|
@@ -794,6 +795,16 @@ private function buildCreateTableSQL(Table $table, bool $createForeignKeys): arr | |
$options['primary'] = []; | ||
|
||
foreach ($table->getIndexes() as $index) { | ||
if ($index->isFunctional() && ! $this->supportsFunctionalIndex()) { | ||
throw new InvalidArgumentException(sprintf( | ||
'Index "%s" on table "%s" contains a functional part, ' . | ||
'but platform "%s" does not support functional indexes.', | ||
$index->getName(), | ||
$table->getName(), | ||
get_debug_type($this), | ||
)); | ||
} | ||
|
||
if (! $index->isPrimary()) { | ||
$options['indexes'][$index->getQuotedName($this)] = $index; | ||
|
||
|
@@ -1081,6 +1092,16 @@ public function getCreateIndexSQL(Index $index, string $table): string | |
)); | ||
} | ||
|
||
if ($index->isFunctional() && ! $this->supportsFunctionalIndex()) { | ||
throw new InvalidArgumentException(sprintf( | ||
'Index "%s" on table "%s" contains a functional part, ' . | ||
'but platform "%s" does not support functional indexes.', | ||
$name, | ||
$table, | ||
get_debug_type($this), | ||
)); | ||
} | ||
|
||
if ($index->isPrimary()) { | ||
return $this->getCreatePrimaryKeySQL($index, $table); | ||
} | ||
|
@@ -1533,6 +1554,15 @@ public function getIndexDeclarationSQL(Index $index): string | |
throw new InvalidArgumentException('Incomplete definition. "columns" required.'); | ||
} | ||
|
||
if ($index->isFunctional() && ! $this->supportsFunctionalIndex()) { | ||
throw new InvalidArgumentException(sprintf( | ||
'Index "%s" contains a functional part, ' . | ||
'but platform "%s" does not support functional indexes.', | ||
$index->getName(), | ||
get_debug_type($this), | ||
)); | ||
} | ||
|
||
return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $index->getQuotedName($this) | ||
. ' (' . implode(', ', $index->getQuotedColumns($this)) . ')' . $this->getPartialIndexSQL($index); | ||
} | ||
|
@@ -1973,6 +2003,14 @@ public function supportsColumnCollation(): bool | |
return false; | ||
} | ||
|
||
/** | ||
* A flag that indicates whether the platform supports functional indexes. | ||
*/ | ||
public function supportsFunctionalIndex(): bool | ||
{ | ||
return true; | ||
} | ||
Comment on lines
+2006
to
+2012
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Repeating myself: I don't think we need this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why we have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The difference is that the method in question was introduced in 2014 and we have 2024 now. Quoting myself:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can't figure out what the alternative is? If you told me this approach is wrong, what is the right approach? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can change the code, but I can't read your thoughts on it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Create a new method in the platform classes that renders DDL for a functional index. Let it throw by default. Override that method inside the platform classes that support functional indexes.
No, we don't. |
||
|
||
/** | ||
* Gets the format string, as accepted by the date() function, that describes | ||
* the format of a stored datetime value of this platform. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Doctrine\DBAL\Platforms; | ||
|
||
/** | ||
* Provides features of the MySQL since 8.0.13 database platform. | ||
* | ||
* Note: Should not be used with versions prior to 8.0.13. | ||
*/ | ||
class MySQL8013Platform extends MySQLPlatform | ||
{ | ||
public function getColumnOrExpressionNameForIndexFetching(): string | ||
{ | ||
return <<<'SQL' | ||
COALESCE( | ||
COLUMN_NAME, | ||
(CASE WHEN SUBSTR(EXPRESSION, 1, 1) != '(' | ||
THEN CONCAT('(', REPLACE(EXPRESSION, '\'', ''''), ')') | ||
ELSE REPLACE(EXPRESSION, '\'', '''') | ||
END) | ||
) | ||
SQL; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,7 @@ | |
use function array_values; | ||
use function count; | ||
use function explode; | ||
use function get_debug_type; | ||
use function implode; | ||
use function sprintf; | ||
use function str_replace; | ||
|
@@ -561,6 +562,16 @@ public function getCreateIndexSQL(Index $index, string $table): string | |
)); | ||
} | ||
|
||
if ($index->isFunctional() && ! $this->supportsFunctionalIndex()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're inside a platform class for SQLite. We should know whether SQLite supports functional indexes. |
||
throw new InvalidArgumentException(sprintf( | ||
'Index "%s" on table "%s" contains a functional part, ' . | ||
'but platform "%s" does not support functional indexes.', | ||
$name, | ||
$table, | ||
get_debug_type($this), | ||
)); | ||
} | ||
|
||
if ($index->isPrimary()) { | ||
return $this->getCreatePrimaryKeySQL($index, $table); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,8 @@ | |
use function array_search; | ||
use function array_shift; | ||
use function count; | ||
use function str_ends_with; | ||
use function str_starts_with; | ||
use function strtolower; | ||
|
||
class Index extends AbstractAsset | ||
|
@@ -27,6 +29,8 @@ class Index extends AbstractAsset | |
|
||
protected bool $_isPrimary = false; | ||
|
||
protected bool $_isFunctional = false; | ||
|
||
/** | ||
* Platform specific flags for indexes. | ||
* | ||
|
@@ -58,6 +62,12 @@ public function __construct( | |
|
||
foreach ($columns as $column) { | ||
$this->_addColumn($column); | ||
|
||
if ($this->_isFunctional === true) { | ||
continue; | ||
} | ||
|
||
$this->_isFunctional = self::isColumnNameAnExpression($column); | ||
} | ||
|
||
foreach ($flags as $flag) { | ||
|
@@ -101,10 +111,14 @@ public function getQuotedColumns(AbstractPlatform $platform): array | |
foreach ($this->_columns as $column) { | ||
$length = array_shift($subParts); | ||
|
||
$quotedColumn = $column->getQuotedName($platform); | ||
if ($this->isFunctional()) { | ||
$quotedColumn = $column->getName(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A functional column does not have a name. We should find a better representation for such columns. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And which representation is better :) Even in databases, functional indexes are stored in a hackish way. |
||
} else { | ||
$quotedColumn = $column->getQuotedName($platform); | ||
|
||
if ($length !== null) { | ||
$quotedColumn .= '(' . $length . ')'; | ||
if ($length !== null) { | ||
$quotedColumn .= '(' . $length . ')'; | ||
} | ||
} | ||
|
||
$columns[] = $quotedColumn; | ||
|
@@ -137,6 +151,11 @@ public function isPrimary(): bool | |
return $this->_isPrimary; | ||
} | ||
|
||
public function isFunctional(): bool | ||
{ | ||
return $this->_isFunctional; | ||
} | ||
|
||
public function hasColumnAtPosition(string $name, int $pos = 0): bool | ||
{ | ||
$name = $this->trimQuotes(strtolower($name)); | ||
|
@@ -283,6 +302,11 @@ public function getOptions(): array | |
return $this->options; | ||
} | ||
|
||
public static function isColumnNameAnExpression(string $columnName): bool | ||
{ | ||
return str_starts_with($columnName, '(') && str_ends_with($columnName, ')'); | ||
} | ||
|
||
/** | ||
* Return whether the two indexes have the same partial index | ||
*/ | ||
|
Uh oh!
There was an error while loading. Please reload this page.