Merge pull request #9456 from open-sausages/pulls/4/avoid-tempdatabase-infinite-loop

BUG Infinite loops in TempDatabase (fixes #8902)
This commit is contained in:
Loz Calver 2020-04-09 09:28:57 +01:00 committed by GitHub
commit 3ad4b93daa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -24,6 +24,13 @@ class TempDatabase
*/ */
protected $name = null; protected $name = null;
/**
* Workaround to avoid infinite loops.
*
* @var Exception
*/
private $skippedException = null;
/** /**
* Optionally remove the test DB when the PHP process exits * Optionally remove the test DB when the PHP process exits
* *
@ -232,29 +239,36 @@ class TempDatabase
$dataClasses = ClassInfo::subclassesFor(DataObject::class); $dataClasses = ClassInfo::subclassesFor(DataObject::class);
array_shift($dataClasses); array_shift($dataClasses);
$oldCheckAndRepairOnBuild = Config::inst()->get(DBSchemaManager::class, 'check_and_repair_on_build');
Config::modify()->set(DBSchemaManager::class, 'check_and_repair_on_build', false);
$schema = $this->getConn()->getSchemaManager(); $schema = $this->getConn()->getSchemaManager();
$schema->quiet(); $schema->quiet();
$schema->schemaUpdate(function () use ($dataClasses, $extraDataObjects) { $schema->schemaUpdate(
foreach ($dataClasses as $dataClass) { function () use ($dataClasses, $extraDataObjects) {
// Check if class exists before trying to instantiate - this sidesteps any manifest weirdness foreach ($dataClasses as $dataClass) {
if (class_exists($dataClass)) { // Check if class exists before trying to instantiate - this sidesteps any manifest weirdness
$SNG = singleton($dataClass); if (class_exists($dataClass)) {
if (!($SNG instanceof TestOnly)) { $SNG = singleton($dataClass);
$SNG->requireTable(); if (!($SNG instanceof TestOnly)) {
$SNG->requireTable();
}
} }
} }
}
// If we have additional dataobjects which need schema, do so here: // If we have additional dataobjects which need schema, do so here:
if ($extraDataObjects) { if ($extraDataObjects) {
foreach ($extraDataObjects as $dataClass) { foreach ($extraDataObjects as $dataClass) {
$SNG = singleton($dataClass); $SNG = singleton($dataClass);
if (singleton($dataClass) instanceof DataObject) { if (singleton($dataClass) instanceof DataObject) {
$SNG->requireTable(); $SNG->requireTable();
}
} }
} }
} }
}); );
Config::modify()->set(DBSchemaManager::class, 'check_and_repair_on_build', $oldCheckAndRepairOnBuild);
ClassInfo::reset_db_cache(); ClassInfo::reset_db_cache();
DataObject::singleton()->flushCache(); DataObject::singleton()->flushCache();
@ -293,6 +307,13 @@ class TempDatabase
try { try {
$this->rebuildTables($extraDataObjects); $this->rebuildTables($extraDataObjects);
} catch (DatabaseException $ex) { } catch (DatabaseException $ex) {
// Avoid infinite loops
if ($this->skippedException && $this->skippedException->getMessage() == $ex->getMessage()) {
throw $ex;
}
$this->skippedException = $ex;
// In case of error during build force a hard reset // In case of error during build force a hard reset
// e.g. pgsql doesn't allow schema updates inside transactions // e.g. pgsql doesn't allow schema updates inside transactions
$this->kill(); $this->kill();