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;
/**
* Workaround to avoid infinite loops.
*
* @var Exception
*/
private $skippedException = null;
/**
* Optionally remove the test DB when the PHP process exits
*
@ -232,29 +239,36 @@ class TempDatabase
$dataClasses = ClassInfo::subclassesFor(DataObject::class);
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->quiet();
$schema->schemaUpdate(function () use ($dataClasses, $extraDataObjects) {
foreach ($dataClasses as $dataClass) {
// Check if class exists before trying to instantiate - this sidesteps any manifest weirdness
if (class_exists($dataClass)) {
$SNG = singleton($dataClass);
if (!($SNG instanceof TestOnly)) {
$SNG->requireTable();
$schema->schemaUpdate(
function () use ($dataClasses, $extraDataObjects) {
foreach ($dataClasses as $dataClass) {
// Check if class exists before trying to instantiate - this sidesteps any manifest weirdness
if (class_exists($dataClass)) {
$SNG = singleton($dataClass);
if (!($SNG instanceof TestOnly)) {
$SNG->requireTable();
}
}
}
}
// If we have additional dataobjects which need schema, do so here:
if ($extraDataObjects) {
foreach ($extraDataObjects as $dataClass) {
$SNG = singleton($dataClass);
if (singleton($dataClass) instanceof DataObject) {
$SNG->requireTable();
// If we have additional dataobjects which need schema, do so here:
if ($extraDataObjects) {
foreach ($extraDataObjects as $dataClass) {
$SNG = singleton($dataClass);
if (singleton($dataClass) instanceof DataObject) {
$SNG->requireTable();
}
}
}
}
});
);
Config::modify()->set(DBSchemaManager::class, 'check_and_repair_on_build', $oldCheckAndRepairOnBuild);
ClassInfo::reset_db_cache();
DataObject::singleton()->flushCache();
@ -293,6 +307,13 @@ class TempDatabase
try {
$this->rebuildTables($extraDataObjects);
} 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
// e.g. pgsql doesn't allow schema updates inside transactions
$this->kill();