Properly handle foreign keys referencing tables created later on
authorMatthias Schmidt <gravatronics@live.com>
Tue, 13 Apr 2021 14:21:54 +0000 (16:21 +0200)
committerMatthias Schmidt <gravatronics@live.com>
Tue, 13 Apr 2021 14:32:48 +0000 (16:32 +0200)
If a foreign key of the first table references a table to be created later on, this foreign key can only be created once the referenced table was created.

wcfsetup/install/files/lib/system/database/table/DatabaseTableChangeProcessor.class.php

index 202065ff00cc47b1ff78942656e249a877096d02..318d517c89e25cec96b91e1aca3c9b728ac4fa9a 100644 (file)
@@ -448,6 +448,12 @@ class DatabaseTableChangeProcessor {
                                                }
                                        }
                                        else if ($matchingExistingForeignKey === null) {
+                                               // If the referenced database table does not already exists, delay the
+                                               // foreign key creation until after the referenced table has been created.
+                                               if (!in_array($foreignKey->getReferencedTable(), $this->existingTableNames)) {
+                                                       continue;
+                                               }
+                                               
                                                if (!isset($this->foreignKeysToAdd[$tableName])) {
                                                        $this->foreignKeysToAdd[$tableName] = [];
                                                }
@@ -648,10 +654,18 @@ class DatabaseTableChangeProcessor {
                $this->dbEditor->createTable($table->getName(), $columnData, $indexData);
                
                foreach ($table->getForeignKeys() as $foreignKey) {
-                       $this->dbEditor->addForeignKey($table->getName(), $foreignKey->getName(), $foreignKey->getData());
-                       
-                       // foreign keys need to be explicitly logged for proper uninstallation
-                       $this->createForeignKeyLog($table->getName(), $foreignKey);
+                       // Only try to create the foreign key if the referenced database table already exists.
+                       // If it will be created later on, delay the foreign key creation until after the
+                       // referenced table has been created.
+                       if (
+                               in_array($foreignKey->getReferencedTable(), $this->existingTableNames)
+                               || $foreignKey->getReferencedTable() === $table->getName()
+                       ) {
+                               $this->dbEditor->addForeignKey($table->getName(), $foreignKey->getName(), $foreignKey->getData());
+                               
+                               // foreign keys need to be explicitly logged for proper uninstallation
+                               $this->createForeignKeyLog($table->getName(), $foreignKey);
+                       }
                }
        }