Skip to content

Commit

Permalink
Add MySQL support for expression indexes
Browse files Browse the repository at this point in the history
  • Loading branch information
Ioannis Igoumenos committed Oct 22, 2023
1 parent c2b637c commit 3492096
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 4 deletions.
76 changes: 76 additions & 0 deletions app/src/Lib/Util/CmgMySQLSchemaManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace App\Lib\Util;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Result;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\Identifier;
use Doctrine\DBAL\Schema\MySQLSchemaManager;

class CmgMySQLSchemaManager extends MySQLSchemaManager {
/**
* Aggregates and groups the index results according to the required data result.
* Parameters: \mixed[][] $tableIndexes
* null|string $tableName
*/

protected function _getPortableTableIndexesList($tableIndexes, $tableName = null)
{
foreach ($tableIndexes as $k => $v) {
$v = array_change_key_case($v, CASE_LOWER);
if ($v['key_name'] === 'PRIMARY') {
$v['primary'] = true;
} else {
$v['primary'] = false;
}

if (strpos($v['index_type'], 'FULLTEXT') !== false) {
$v['flags'] = ['FULLTEXT'];
} elseif (strpos($v['index_type'], 'SPATIAL') !== false) {
$v['flags'] = ['SPATIAL'];
}

// Ignore prohibited prefix `length` for spatial index
if (strpos($v['index_type'], 'SPATIAL') === false) {
$v['length'] = isset($v['sub_part']) ? (int) $v['sub_part'] : null;
}

$tableIndexes[$k] = $v;
}

return AbstractSchemaManager::_getPortableTableIndexesList($tableIndexes, $tableName);
}

protected function selectIndexColumns(string $databaseName, ?string $tableName = null): Result
{
$sql = 'SELECT';

if ($tableName === null) {
$sql .= ' TABLE_NAME,';
}

$sql .= <<<'SQL'
NON_UNIQUE AS Non_Unique,
INDEX_NAME AS Key_name,
CONCAT(COALESCE(COLUMN_NAME, ''), COALESCE(EXPRESSION, '')) AS Column_Name,
SUB_PART AS Sub_Part,
INDEX_TYPE AS Index_Type,
EXPRESSION AS Expression
FROM information_schema.STATISTICS
SQL;

$conditions = ['TABLE_SCHEMA = ?'];
$params = [$databaseName];

if ($tableName !== null) {
$conditions[] = 'TABLE_NAME = ?';
$params[] = $tableName;
}

$sql .= ' WHERE ' . implode(' AND ', $conditions) . ' ORDER BY SEQ_IN_INDEX';

return $this->_conn->executeQuery($sql, $params);
}

}
2 changes: 1 addition & 1 deletion app/src/Lib/Util/CmgPostgreSQLSchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null
foreach ($tableIndexes as $row) {
$colNumbers = array_map('intval', explode(' ', $row['indkey']));
$colNames = explode("," , trim($row["indkey_names"], "{,}"));
$colNumName = array_combine($colNumbers, $colNames);
$colNumName = array_combine($colNumbers, $colNames);

// required for getting the order of the columns right.
foreach ($colNumName as $colNum => $colName) {
Expand Down
7 changes: 7 additions & 0 deletions app/src/Lib/Util/CmgSchemaManagerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
namespace App\Lib\Util;

use App\Lib\Util\CmgPostgreSQLSchemaManager;
use App\Lib\Util\CmgMySQLSchemaManager;
use Doctrine\DBAL\Driver\AbstractPostgreSQLDriver;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\MySQL80Platform;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
use Doctrine\DBAL\Schema\SchemaManagerFactory;
Expand All @@ -29,6 +32,10 @@ public function createSchemaManager(Connection $connection): AbstractSchemaManag
return new CmgPostgreSQLSchemaManager($connection, $platform);
}

if ($platform instanceof MySQLPlatform) {
return new CmgMySQLSchemaManager($connection, $platform);
}

return $this->defaultFactory->createSchemaManager($connection);
}
}
20 changes: 17 additions & 3 deletions app/src/Lib/Util/SchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,23 @@ protected function processSchema(
// will be executed later. What we actually do is treat the expression
// as a temporary virtual column
// https://www.postgresql.org/docs/14/indexes-expressional.html
// https://dev.mysql.com/doc/refman/8.0/en/create-index.html#create-index-functional-key-parts
// https://www.sqlite.org/expridx.html
// XXX MariadBD is not supported
$tempColumns = [];
foreach ($iCfg->columns as $clm_name) {
foreach ($iCfg->columns as $idx => $clm_name) {
if (! $table->hasColumn($clm_name)) {
if(in_array($this->driver, array(
"Cake\Database\Driver\Mysql",
"Cake\Database\Driver\Sqlite",
))) {
// MySQL requires the column name to be wrapped with parenthesis
// Instead of indexing a simple column, you can create the index on the result
// of any function applied to a column or multiple columns.
// Be aware of the double parentheses. The syntax is correct since the expression
// must be enclosed within parentheses to distinguish it from columns or column prefixes.
$iCfg->columns[$idx] = $clm_name = "({$clm_name})";
}
$table->addColumn($clm_name, "string");
$tempColumns[] = $clm_name;
}
Expand All @@ -294,7 +308,7 @@ protected function processSchema(

// (For Registry) If an attribute is "sourced" it is a CO Person attribute
// that is copied via a Pipeline from an External Identity that was created from
// an External Identity Source, so we need a foreign key into ourself.
// an External Identity Source, so we need a foreign key into ourselves.

if(isset($tCfg->sourced) && $tCfg->sourced) {
$sColumn = "source_" . $tablePrefix.\Cake\Utility\Inflector::singularize($tName) . "_id";
Expand Down Expand Up @@ -332,7 +346,7 @@ protected function processSchema(
// SchemaManager provides info about the database
$sm = $this->conn->createSchemaManager();

// The is the current database representation
// This is the current database representation
$curSchema = $sm->introspectSchema();

$fromSql = $curSchema->toSql($this->conn->getDatabasePlatform());
Expand Down

0 comments on commit 3492096

Please sign in to comment.