Skip to content

Commit

Permalink
Merge branch '3.7.x' into 3.8.x
Browse files Browse the repository at this point in the history
* 3.7.x:
  Fix MariaDB list columns performance (#6202)
  • Loading branch information
derrabus committed Nov 5, 2023
2 parents 802633d + 1f1aad9 commit 706007b
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 21 deletions.
12 changes: 11 additions & 1 deletion src/Platforms/AbstractMySQLPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,17 @@ public function getListTableColumnsSQL($table, $database = null)
*/
public function getColumnTypeSQLSnippets(string $tableAlias = 'c'): array
{
return [$tableAlias . '.COLUMN_TYPE', ''];
return [$this->getColumnTypeSQLSnippet(...func_get_args()), ''];
}

/**
* The SQL snippet required to elucidate a column type
*
* Returns a column type SELECT snippet string
*/
public function getColumnTypeSQLSnippet(string $tableAlias = 'c', ?string $databaseName = null): string
{
return $tableAlias . '.COLUMN_TYPE';
}

/** @deprecated The SQL used for schema introspection is an implementation detail and should not be relied upon. */
Expand Down
39 changes: 20 additions & 19 deletions src/Platforms/MariaDb1043Platform.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ public function getJsonTypeDeclarationSQL(array $column): string
*/
public function getListTableColumnsSQL($table, $database = null): string
{
[$columnTypeSQL, $joinCheckConstraintSQL] = $this->getColumnTypeSQLSnippets();
// @todo 4.0 - call getColumnTypeSQLSnippet() instead
[$columnTypeSQL, $joinCheckConstraintSQL] = $this->getColumnTypeSQLSnippets('c', $database);

return sprintf(
<<<SQL
Expand Down Expand Up @@ -72,34 +73,34 @@ public function getListTableColumnsSQL($table, $database = null): string
* is valid json. This function generates the SQL snippets which reverse this aliasing i.e. report a column
* as JSON where it was originally specified as such instead of LONGTEXT.
*
* The CHECK constraints are stored in information_schema.CHECK_CONSTRAINTS so JOIN that table.
*
* @return array{string, string}
* The CHECK constraints are stored in information_schema.CHECK_CONSTRAINTS so query that table.
*/
public function getColumnTypeSQLSnippets(string $tableAlias = 'c'): array
public function getColumnTypeSQLSnippet(string $tableAlias = 'c', ?string $databaseName = null): string
{
if ($this->getJsonTypeDeclarationSQL([]) !== 'JSON') {
return parent::getColumnTypeSQLSnippets($tableAlias);
return parent::getColumnTypeSQLSnippet($tableAlias, $databaseName);
}

$columnTypeSQL = <<<SQL
$databaseName = $this->getDatabaseNameSQL($databaseName);

// The check for `CONSTRAINT_SCHEMA = $databaseName` is mandatory here to prevent performance issues
return <<<SQL
IF(
x.CHECK_CLAUSE IS NOT NULL AND $tableAlias.COLUMN_TYPE = 'longtext',
$tableAlias.COLUMN_TYPE = 'longtext'
AND EXISTS(
SELECT * from information_schema.CHECK_CONSTRAINTS
WHERE CONSTRAINT_SCHEMA = $databaseName
AND TABLE_NAME = $tableAlias.TABLE_NAME
AND CHECK_CLAUSE = CONCAT(
'json_valid(`',
$tableAlias.COLUMN_NAME,
'`)'
)
),
'json',
$tableAlias.COLUMN_TYPE
)
SQL;

$joinCheckConstraintSQL = <<<SQL
LEFT JOIN information_schema.CHECK_CONSTRAINTS x
ON (
$tableAlias.TABLE_SCHEMA = x.CONSTRAINT_SCHEMA
AND $tableAlias.TABLE_NAME = x.TABLE_NAME
AND x.CHECK_CLAUSE = CONCAT('json_valid(`', $tableAlias.COLUMN_NAME , '`)')
)
SQL;

return [$columnTypeSQL, $joinCheckConstraintSQL];
}

/** {@inheritDoc} */
Expand Down
3 changes: 2 additions & 1 deletion src/Schema/MySQLSchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,8 @@ protected function selectTableNames(string $databaseName): Result

protected function selectTableColumns(string $databaseName, ?string $tableName = null): Result
{
[$columnTypeSQL, $joinCheckConstraintSQL] = $this->_platform->getColumnTypeSQLSnippets();
// @todo 4.0 - call getColumnTypeSQLSnippet() instead
[$columnTypeSQL, $joinCheckConstraintSQL] = $this->_platform->getColumnTypeSQLSnippets('c', $databaseName);

$sql = 'SELECT';

Expand Down
6 changes: 6 additions & 0 deletions tests/Functional/Schema/MySQLSchemaManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Doctrine\DBAL\Platforms\AbstractMySQLPlatform;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\MariaDb1027Platform;
use Doctrine\DBAL\Platforms\MariaDb1043Platform;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Tests\Functional\Schema\MySQL\PointType;
Expand Down Expand Up @@ -401,6 +402,11 @@ public function testJsonColumnType(): void
$table->addColumn('col_json', Types::JSON);
$this->dropAndCreateTable($table);

// Remove the comment from the column to ensure the type is detected correctly from the check constraints.
if ($this->connection->getDatabasePlatform() instanceof MariaDb1043Platform) {
$this->connection->executeStatement('ALTER TABLE test_mysql_json CHANGE COLUMN col_json col_json JSON');
}

$columns = $this->schemaManager->listTableColumns('test_mysql_json');

self::assertSame(Types::JSON, $columns['col_json']->getType()->getName());
Expand Down

0 comments on commit 706007b

Please sign in to comment.