diff --git a/src/ORM/Connect/TempDatabase.php b/src/ORM/Connect/TempDatabase.php index a47c50078..208662250 100644 --- a/src/ORM/Connect/TempDatabase.php +++ b/src/ORM/Connect/TempDatabase.php @@ -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();