[DATABASE] Change collation handling

Before now table definitions could define collations only for MariaDB using the
MariaDB's collation names directly.
Now instead definitions get a slightly more abstract collation name syntax, but
only supporting the collations utf8mb4_bin and utf8mb4_unicode_(cs|ci) (wrapped
as utf8_bin, utf8_general_(cs|ci)), because those are the ones that have
practical use for GNU social.

Which also means that on MariaDB the formerly used utf8mb4_general_(cs|ci) have
been superseded by utf8mb4_unicode_(cs|ci), as they are the more modern
replacement.

Introduce collation support on PostgreSQL which results in use of the C (POSIX)
collation as utf8_bin and the und-x-icu collation as utf8_general_cs.
utf8_general_ci is also mapped to und-x-icu, which makes it case-sensitive,
unfortunately.
This commit is contained in:
Alexei Sorokin
2020-08-16 23:41:28 +03:00
parent 5c21816b22
commit 341e34b766
5 changed files with 141 additions and 36 deletions

View File

@@ -891,6 +891,48 @@ class Schema
return null;
}
/**
* Is this column a string type?
*
* @param array $cd
* @return bool
*/
protected function isStringType(array $cd): bool
{
$strings = ['char', 'varchar', 'text'];
$strings[] = 'bpchar'; // PostgreSQL
$strings[] = 'enum'; // MariaDB
return in_array(strtolower($cd['type']), $strings);
}
/**
* Collation in our format from MariaDB format
*
* @param string $collate
* @return string
*/
protected function collationFromMySQL(string $collate): string
{
if (substr($collate, 0, 8) === 'utf8mb4_') {
$collate = 'utf8_' . substr($collate, 8);
}
if (substr($collate, 0, 13) === 'utf8_unicode_') {
$collate = 'utf8_general_' . substr($collate, 13);
}
if (!in_array($collate, [
'utf8_bin',
'utf8_general_cs',
'utf8_general_ci',
])) {
common_log(
LOG_ERR,
'Collation not supported: "' . $collate . '"'
);
$collate = 'utf8_bin';
}
return $collate;
}
/**
* Return the proper SQL for creating or
* altering a column.
@@ -1059,6 +1101,15 @@ class Schema
if (array_key_exists('not null', $col) && $col['not null'] !== true) {
unset($col['not null']);
}
if ($this->isStringType($col)) {
// Default collation
if (empty($col['collate'])) {
$col['collate'] = 'utf8_bin';
}
// Migration from direct MariaDB collations
$col['collate'] = $this->collationFromMySQL($col['collate']);
}
}
if (common_config('search', 'type') !== 'fulltext') {