]> source.dussan.org Git - nextcloud-server.git/commitdiff
feat(db): Ensure that index names are unique across the database
authorJoas Schilling <coding@schilljs.com>
Thu, 20 Jul 2023 12:27:26 +0000 (14:27 +0200)
committerJoas Schilling <coding@schilljs.com>
Thu, 20 Jul 2023 12:27:26 +0000 (14:27 +0200)
Signed-off-by: Joas Schilling <coding@schilljs.com>
lib/private/DB/MigrationService.php

index 3afe2f689f94efd979df58da8f08045ffe835836..71d7b51d149a497db8aabd1f095f5ad0260660f9 100644 (file)
@@ -448,6 +448,7 @@ class MigrationService {
 
                if ($toSchema instanceof SchemaWrapper) {
                        $targetSchema = $toSchema->getWrappedSchema();
+                       $this->ensureUniqueNamesConstraints($targetSchema);
                        if ($this->checkOracle) {
                                $beforeSchema = $this->connection->createSchema();
                                $this->ensureOracleConstraints($beforeSchema, $targetSchema, strlen($this->connection->getPrefix()));
@@ -525,6 +526,7 @@ class MigrationService {
 
                if ($toSchema instanceof SchemaWrapper) {
                        $targetSchema = $toSchema->getWrappedSchema();
+                       $this->ensureUniqueNamesConstraints($targetSchema);
                        if ($this->checkOracle) {
                                $sourceSchema = $this->connection->createSchema();
                                $this->ensureOracleConstraints($sourceSchema, $targetSchema, strlen($this->connection->getPrefix()));
@@ -659,6 +661,59 @@ class MigrationService {
                }
        }
 
+       /**
+        * Naming constraints:
+        * - Index, sequence and primary key names must be unique within a Postgres Schema
+        *
+        * @param Schema $targetSchema
+        */
+       public function ensureUniqueNamesConstraints(Schema $targetSchema): void {
+               $constraintNames = [];
+
+               $sequences = $targetSchema->getSequences();
+
+               foreach ($targetSchema->getTables() as $table) {
+                       foreach ($table->getIndexes() as $thing) {
+                               $indexName = strtolower($thing->getName());
+                               if ($indexName === 'primary' || $thing->isPrimary()) {
+                                       continue;
+                               }
+
+                               if (isset($constraintNames[$thing->getName()])) {
+                                       throw new \InvalidArgumentException('Index name "' . $thing->getName() . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".');
+                               }
+                               $constraintNames[$thing->getName()] = $table->getName();
+                       }
+
+                       foreach ($table->getForeignKeys() as $thing) {
+                               if (isset($constraintNames[$thing->getName()])) {
+                                       throw new \InvalidArgumentException('Foreign key name "' . $thing->getName() . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".');
+                               }
+                               $constraintNames[$thing->getName()] = $table->getName();
+                       }
+
+                       $primaryKey = $table->getPrimaryKey();
+                       if ($primaryKey instanceof Index) {
+                               $indexName = strtolower($primaryKey->getName());
+                               if ($indexName === 'primary') {
+                                       continue;
+                               }
+
+                               if (isset($constraintNames[$indexName])) {
+                                       throw new \InvalidArgumentException('Primary index name "' . $indexName . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".');
+                               }
+                               $constraintNames[$indexName] = $table->getName();
+                       }
+               }
+
+               foreach ($sequences as $sequence) {
+                       if (isset($constraintNames[$sequence->getName()])) {
+                               throw new \InvalidArgumentException('Sequence name "' . $sequence->getName() . '" for table "' . $table->getName() . '" collides with the constraint on table "' . $constraintNames[$thing->getName()] . '".');
+                       }
+                       $constraintNames[$sequence->getName()] = 'sequence';
+               }
+       }
+
        private function ensureMigrationsAreLoaded() {
                if (empty($this->migrations)) {
                        $this->migrations = $this->findMigrations();