Order schema create statements by FK dependencies
This commit is contained in:
parent
47b957bf18
commit
31e7c21dd4
|
|
@ -633,6 +633,8 @@ class Setup extends BaseController
|
||||||
|
|
||||||
$createCount = 0;
|
$createCount = 0;
|
||||||
$alterCount = 0;
|
$alterCount = 0;
|
||||||
|
$missingCreateSqlByTable = [];
|
||||||
|
$alterStatements = [];
|
||||||
|
|
||||||
foreach ($masterTables as $table => $masterTableDef) {
|
foreach ($masterTables as $table => $masterTableDef) {
|
||||||
if ($processedTables >= $maxTables) {
|
if ($processedTables >= $maxTables) {
|
||||||
|
|
@ -656,7 +658,7 @@ class Setup extends BaseController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($createSql !== '') {
|
if ($createSql !== '') {
|
||||||
$sql[] = $createSql;
|
$missingCreateSqlByTable[$table] = $createSql;
|
||||||
$createCount++;
|
$createCount++;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -665,13 +667,24 @@ class Setup extends BaseController
|
||||||
$tableAlterSql = $this->buildAlterSqlForTableFromSchema((array) $masterTableDef, $client, $table);
|
$tableAlterSql = $this->buildAlterSqlForTableFromSchema((array) $masterTableDef, $client, $table);
|
||||||
if (!empty($tableAlterSql)) {
|
if (!empty($tableAlterSql)) {
|
||||||
foreach ($tableAlterSql as $stmt) {
|
foreach ($tableAlterSql as $stmt) {
|
||||||
$sql[] = $stmt;
|
$alterStatements[] = $stmt;
|
||||||
}
|
}
|
||||||
$alterCount += count($tableAlterSql);
|
$alterCount += count($tableAlterSql);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!empty($missingCreateSqlByTable)) {
|
||||||
|
$orderedCreateStatements = $this->orderCreateTableStatementsByDependency($missingCreateSqlByTable, array_keys($clientTables));
|
||||||
|
foreach ($orderedCreateStatements as $stmt) {
|
||||||
|
$sql[] = $stmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($alterStatements as $stmt) {
|
||||||
|
$sql[] = $stmt;
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'errors' => $errors,
|
'errors' => $errors,
|
||||||
'sql' => $sql,
|
'sql' => $sql,
|
||||||
|
|
@ -687,6 +700,75 @@ class Setup extends BaseController
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, string> $createSqlByTable
|
||||||
|
* @param array<int, string> $alreadyExistingTables
|
||||||
|
* @return array<int, string>
|
||||||
|
*/
|
||||||
|
private function orderCreateTableStatementsByDependency(array $createSqlByTable, array $alreadyExistingTables): array
|
||||||
|
{
|
||||||
|
$existing = array_fill_keys(array_map(static fn ($t) => strtolower((string) $t), $alreadyExistingTables), true);
|
||||||
|
$pending = $createSqlByTable;
|
||||||
|
$ordered = [];
|
||||||
|
|
||||||
|
while (!empty($pending)) {
|
||||||
|
$progress = false;
|
||||||
|
|
||||||
|
foreach ($pending as $table => $createSql) {
|
||||||
|
$deps = $this->extractReferencedTablesFromCreateSql($createSql);
|
||||||
|
$blocked = false;
|
||||||
|
|
||||||
|
foreach ($deps as $depTable) {
|
||||||
|
$depKey = strtolower($depTable);
|
||||||
|
if (isset($pending[$depTable]) && !isset($existing[$depKey])) {
|
||||||
|
$blocked = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($blocked) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ordered[] = $createSql;
|
||||||
|
$existing[strtolower($table)] = true;
|
||||||
|
unset($pending[$table]);
|
||||||
|
$progress = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($progress) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cycles or unresolved references: keep deterministic fallback order.
|
||||||
|
ksort($pending);
|
||||||
|
foreach ($pending as $table => $createSql) {
|
||||||
|
$ordered[] = $createSql;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ordered;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int, string>
|
||||||
|
*/
|
||||||
|
private function extractReferencedTablesFromCreateSql(string $createSql): array
|
||||||
|
{
|
||||||
|
$refs = [];
|
||||||
|
if (preg_match_all('/REFERENCES\s+`([^`]+)`/i', $createSql, $matches) === 1 || !empty($matches[1])) {
|
||||||
|
foreach ((array) ($matches[1] ?? []) as $table) {
|
||||||
|
$name = trim((string) $table);
|
||||||
|
if ($name !== '') {
|
||||||
|
$refs[] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_values(array_unique($refs));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<int, string> $sqlList
|
* @param array<int, string> $sqlList
|
||||||
* @return array{applied:int,errors:array<int,string>,truncated:bool}
|
* @return array{applied:int,errors:array<int,string>,truncated:bool}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user