Skip oversized index alters to avoid key length 3072 errors
This commit is contained in:
parent
2419d0df7b
commit
a18bc7a0bf
|
|
@ -862,6 +862,10 @@ class Setup extends BaseController
|
|||
continue;
|
||||
}
|
||||
|
||||
if ($this->isIndexTooWideForInnoDb((array) $masterDef, $clientCols)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->shouldSkipUniqueIndexSync($client, $table, (array) $masterDef, $clientCols)) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -875,6 +879,10 @@ class Setup extends BaseController
|
|||
continue;
|
||||
}
|
||||
|
||||
if ($this->isIndexTooWideForInnoDb((array) $masterDef, $clientCols)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->shouldSkipUniqueIndexSync($client, $table, (array) $masterDef, $clientCols)) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1371,9 +1379,92 @@ class Setup extends BaseController
|
|||
return true;
|
||||
}
|
||||
|
||||
if (str_contains($messageLower, 'specified key was too long') && str_contains($messageLower, 'max key length is 3072') && str_contains($stmtLower, 'alter table')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $idxDef
|
||||
* @param array<string, array<string, mixed>> $clientCols
|
||||
*/
|
||||
private function isIndexTooWideForInnoDb(array $idxDef, array $clientCols): bool
|
||||
{
|
||||
$columns = array_values(array_filter(array_map(static fn ($col) => (string) $col, (array) ($idxDef['columns'] ?? []))));
|
||||
if (empty($columns)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$totalBytes = 0;
|
||||
foreach ($columns as $column) {
|
||||
$colMeta = $clientCols[$column] ?? null;
|
||||
if (!is_array($colMeta)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$totalBytes += $this->estimateIndexedColumnBytes($colMeta);
|
||||
if ($totalBytes > 3072) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return $totalBytes > 3072;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $colMeta
|
||||
*/
|
||||
private function estimateIndexedColumnBytes(array $colMeta): int
|
||||
{
|
||||
$type = strtolower(trim((string) ($colMeta['Type'] ?? '')));
|
||||
$collation = strtolower(trim((string) ($colMeta['Collation'] ?? '')));
|
||||
|
||||
$bytesPerChar = 1;
|
||||
if ($collation !== '') {
|
||||
if (str_starts_with($collation, 'utf32_')) {
|
||||
$bytesPerChar = 4;
|
||||
} elseif (str_starts_with($collation, 'utf8mb4_')) {
|
||||
$bytesPerChar = 4;
|
||||
} elseif (str_starts_with($collation, 'utf8mb3_') || str_starts_with($collation, 'utf8_')) {
|
||||
$bytesPerChar = 3;
|
||||
} elseif (str_starts_with($collation, 'ucs2_')) {
|
||||
$bytesPerChar = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match('/^(char|varchar)\((\d+)\)/i', $type, $m) === 1) {
|
||||
return (int) $m[2] * $bytesPerChar;
|
||||
}
|
||||
|
||||
if (preg_match('/^(binary|varbinary)\((\d+)\)/i', $type, $m) === 1) {
|
||||
return (int) $m[2];
|
||||
}
|
||||
|
||||
if (preg_match('/^tinytext|^text|^mediumtext|^longtext|^tinyblob|^blob|^mediumblob|^longblob/i', $type) === 1) {
|
||||
return 4096;
|
||||
}
|
||||
|
||||
if (preg_match('/^tinyint/i', $type) === 1) {
|
||||
return 1;
|
||||
}
|
||||
if (preg_match('/^smallint/i', $type) === 1) {
|
||||
return 2;
|
||||
}
|
||||
if (preg_match('/^mediumint/i', $type) === 1) {
|
||||
return 3;
|
||||
}
|
||||
if (preg_match('/^(int|integer)/i', $type) === 1) {
|
||||
return 4;
|
||||
}
|
||||
if (preg_match('/^bigint/i', $type) === 1) {
|
||||
return 8;
|
||||
}
|
||||
|
||||
return 64;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $idxDef
|
||||
* @param array<string, array<string, mixed>> $clientCols
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user