fail("db/migrations.sql fehlt"); return; } $sql = file_get_contents($sqlPath); // Kommentare entfernen $sqlNoComments = preg_replace('/--.*$/m', '', $sql); $sqlNoComments = preg_replace('/\/\*.*?\*\//s', '', $sqlNoComments); // CREATE TABLE ohne IF NOT EXISTS if (preg_match_all('/\bCREATE\s+TABLE\b(?!\s+IF\s+NOT\s+EXISTS)/i', $sqlNoComments, $m1)) { $r->fail("CREATE TABLE muss 'IF NOT EXISTS' haben (Idempotenz)", $m1[0]); } // ALTER TABLE ... ADD COLUMN ohne IF NOT EXISTS if (preg_match_all('/\bADD\s+COLUMN\b(?!\s+IF\s+NOT\s+EXISTS)/i', $sqlNoComments, $m2)) { $r->fail("ADD COLUMN muss 'IF NOT EXISTS' haben (Idempotenz)", $m2[0]); } // DROP-Statements verboten (außer in Kommentaren, die wir entfernt haben) if (preg_match('/\bDROP\s+(TABLE|COLUMN|INDEX)\b/i', $sqlNoComments)) { $r->fail("DROP-Statements in migrations.sql verboten (additive Migration!)"); } // TRUNCATE verboten if (preg_match('/\bTRUNCATE\b/i', $sqlNoComments)) { $r->fail("TRUNCATE in migrations.sql verboten"); } // RENAME verboten if (preg_match('/\bRENAME\b/i', $sqlNoComments)) { $r->fail("RENAME-Statements verboten (additive Migration!)"); } // Tabellen-Prefix prüfen if (!empty($m['slug'])) { $expectedPrefix = "m_{$m['slug']}_"; if (preg_match_all('/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?`?(\w+)`?/i', $sqlNoComments, $tm)) { foreach ($tm[1] as $tbl) { if (!str_starts_with($tbl, $expectedPrefix)) { $r->fail("Tabelle '$tbl' muss Prefix '$expectedPrefix' haben"); } } } } // Wenn nichts gefehlerts: OK $hasContent = trim(preg_replace('/\s+/', '', $sqlNoComments)) !== ''; if ($hasContent) { $r->ok("migrations.sql ist idempotent (CREATE/ALTER mit IF NOT EXISTS, keine DROP/TRUNCATE/RENAME)"); } else { $r->ok("migrations.sql ist leer (Modul ohne eigene Tabellen)"); } }