Add schema-sync retries/skips for FK and collation edge cases

This commit is contained in:
DevSoftTech Server 2026-02-28 23:25:31 +05:30
parent b7f04316a4
commit 0b256777e0

View File

@ -384,7 +384,26 @@ class Setup extends BaseController
$client->query($stmt);
$applied++;
} catch (\Throwable $e) {
$errors[] = $e->getMessage() . ' | SQL: ' . mb_substr($stmt, 0, 180);
$message = (string) $e->getMessage();
if ($this->isSafeToSkipSyncStatement($message, $stmt)) {
continue;
}
if ($this->isCreateTableStatement($stmt) && stripos($message, 'Cannot add foreign key constraint') !== false) {
$retry = $this->stripForeignKeysFromCreateTable($stmt);
if ($retry !== $stmt && $retry !== '') {
try {
$client->query($retry);
$applied++;
continue;
} catch (\Throwable $retryError) {
$message = (string) $retryError->getMessage();
}
}
}
$errors[] = $message . ' | SQL: ' . mb_substr($stmt, 0, 180);
}
}
@ -741,8 +760,9 @@ class Setup extends BaseController
return '';
}
$fallbackCollation = $this->normalizeCollationName('utf8mb4_0900_ai_ci');
$sql = preg_replace('/\bDEFAULT_GENERATED\b/i', '', $sql) ?? $sql;
$sql = preg_replace('/\bCOLLATE\s+utf8mb4_0900_[a-z0-9_]+\b/i', 'COLLATE ' . $this->normalizeCollationName('utf8mb4_0900_ai_ci'), $sql) ?? $sql;
$sql = preg_replace('/\butf8mb4_0900_[a-z0-9_]+\b/i', $fallbackCollation, $sql) ?? $sql;
$sql = preg_replace('/^CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)+/i', 'CREATE TABLE IF NOT EXISTS ', $sql, 1) ?? $sql;
$sql = preg_replace('/\s+/', ' ', $sql) ?? $sql;
$sql = preg_replace('/\s+;$/', ';', $sql) ?? $sql;
@ -750,6 +770,50 @@ class Setup extends BaseController
return trim($sql);
}
private function isCreateTableStatement(string $stmt): bool
{
return preg_match('/^CREATE\s+TABLE\s+/i', ltrim($stmt)) === 1;
}
private function isSafeToSkipSyncStatement(string $message, string $stmt): bool
{
$messageLower = strtolower($message);
$stmtLower = strtolower($stmt);
if (str_contains($messageLower, 'used in a foreign key constraint') && str_contains($stmtLower, 'alter table')) {
return true;
}
if (str_contains($messageLower, 'blob/text column') && str_contains($messageLower, 'key specification without a key length')) {
return true;
}
return false;
}
private function stripForeignKeysFromCreateTable(string $stmt): string
{
$out = $stmt;
$patterns = [
'/\s*,\s*CONSTRAINT\s+`[^`]+`\s+FOREIGN\s+KEY\s*\([^\)]*\)\s*REFERENCES\s*`[^`]+`\s*\([^\)]*\)(?:\s+ON\s+DELETE\s+[A-Z_ ]+)?(?:\s+ON\s+UPDATE\s+[A-Z_ ]+)?/i',
'/\s*,\s*FOREIGN\s+KEY\s*\([^\)]*\)\s*REFERENCES\s*`[^`]+`\s*\([^\)]*\)(?:\s+ON\s+DELETE\s+[A-Z_ ]+)?(?:\s+ON\s+UPDATE\s+[A-Z_ ]+)?/i',
];
foreach ($patterns as $pattern) {
$out = preg_replace($pattern, '', $out) ?? $out;
}
$out = preg_replace('/,\s*\)/', ')', $out) ?? $out;
$out = preg_replace('/\s+/', ' ', $out) ?? $out;
$out = trim($out);
if ($out !== '' && !str_ends_with($out, ';')) {
$out .= ';';
}
return $this->normalizeSyncSql($out);
}
private function indexDefinitionSql(array $idx): string
{
$name = (string) ($idx['name'] ?? '');