From 0bf738d8cb13d48725f9632ddd642e7cf81f5624 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 20 Jul 2023 14:27:26 +0200 Subject: [PATCH 1/2] feat(db): Ensure that index names are unique across the database Signed-off-by: Joas Schilling --- lib/private/DB/MigrationService.php | 55 +++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/lib/private/DB/MigrationService.php b/lib/private/DB/MigrationService.php index 3afe2f689f94e..71d7b51d149a4 100644 --- a/lib/private/DB/MigrationService.php +++ b/lib/private/DB/MigrationService.php @@ -448,6 +448,7 @@ public function migrateSchemaOnly($to = 'latest') { 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 @@ public function executeStep($version, $schemaOnly = false) { 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 @@ public function ensureOracleConstraints(Schema $sourceSchema, Schema $targetSche } } + /** + * 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(); From b80692d323ed2bedec5593fa7ae94fdd02d7186c Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 21 Jul 2023 12:17:36 +0200 Subject: [PATCH 2/2] fix(tests): Adjust unit tests to outline the schema is checked twice now Signed-off-by: Joas Schilling --- tests/lib/DB/MigrationsTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/lib/DB/MigrationsTest.php b/tests/lib/DB/MigrationsTest.php index b7d49b565ac1e..d982a47623bcd 100644 --- a/tests/lib/DB/MigrationsTest.php +++ b/tests/lib/DB/MigrationsTest.php @@ -101,10 +101,10 @@ public function testExecuteStepWithSchemaChange() { ->method('migrateToSchema'); $wrappedSchema = $this->createMock(Schema::class); - $wrappedSchema->expects($this->once()) + $wrappedSchema->expects($this->exactly(2)) ->method('getTables') ->willReturn([]); - $wrappedSchema->expects($this->once()) + $wrappedSchema->expects($this->exactly(2)) ->method('getSequences') ->willReturn([]);