diff --git a/lib/Command/Db/CleanMigrations.php b/lib/Command/Db/CleanMigrations.php index f590d9021f..d9e271caa5 100644 --- a/lib/Command/Db/CleanMigrations.php +++ b/lib/Command/Db/CleanMigrations.php @@ -10,7 +10,7 @@ use Doctrine\DBAL\Schema\Schema; use OCA\Polls\Command\Command; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCP\IDBConnection; /** diff --git a/lib/Command/Db/CreateIndices.php b/lib/Command/Db/CreateIndices.php index 809f1e0971..163a8a4644 100644 --- a/lib/Command/Db/CreateIndices.php +++ b/lib/Command/Db/CreateIndices.php @@ -10,7 +10,7 @@ use Doctrine\DBAL\Schema\Schema; use OCA\Polls\Command\Command; -use OCA\Polls\Db\V6\IndexManager; +use OCA\Polls\Db\V7\IndexManager; use OCP\IDBConnection; /** diff --git a/lib/Command/Db/FixDB.php b/lib/Command/Db/FixDB.php index 9974936b18..e241f7d189 100644 --- a/lib/Command/Db/FixDB.php +++ b/lib/Command/Db/FixDB.php @@ -10,7 +10,7 @@ use Doctrine\DBAL\Schema\Schema; use OCA\Polls\Command\Command; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCP\IDBConnection; /** diff --git a/lib/Command/Db/Purge.php b/lib/Command/Db/Purge.php index 52a9e73083..6214a26f73 100644 --- a/lib/Command/Db/Purge.php +++ b/lib/Command/Db/Purge.php @@ -9,7 +9,7 @@ namespace OCA\Polls\Command\Db; use OCA\Polls\Command\Command; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCP\IDBConnection; /** diff --git a/lib/Command/Db/Rebuild.php b/lib/Command/Db/Rebuild.php index de67769706..d585c69416 100644 --- a/lib/Command/Db/Rebuild.php +++ b/lib/Command/Db/Rebuild.php @@ -9,8 +9,8 @@ namespace OCA\Polls\Command\Db; use Doctrine\DBAL\Schema\Schema; -use OCA\Polls\Db\V6\TableManager; -use OCA\Polls\Db\V6\IndexManager; +use OCA\Polls\Db\V7\TableManager; +use OCA\Polls\Db\V7\IndexManager; use OCA\Polls\Command\Command; use OCP\IDBConnection; diff --git a/lib/Command/Db/RemoveFKConstraints.php b/lib/Command/Db/RemoveFKConstraints.php index f276543bba..e5e57c6000 100644 --- a/lib/Command/Db/RemoveFKConstraints.php +++ b/lib/Command/Db/RemoveFKConstraints.php @@ -10,7 +10,7 @@ use Doctrine\DBAL\Schema\Schema; use OCA\Polls\Command\Command; -use OCA\Polls\Db\V6\IndexManager; +use OCA\Polls\Db\V7\IndexManager; use OCP\IDBConnection; /** diff --git a/lib/Command/Db/RemoveOptionalIndices.php b/lib/Command/Db/RemoveOptionalIndices.php index 080a47cf8a..e3d5637188 100644 --- a/lib/Command/Db/RemoveOptionalIndices.php +++ b/lib/Command/Db/RemoveOptionalIndices.php @@ -10,7 +10,7 @@ use Doctrine\DBAL\Schema\Schema; use OCA\Polls\Command\Command; -use OCA\Polls\Db\V6\IndexManager; +use OCA\Polls\Db\V7\IndexManager; use OCP\IDBConnection; /** diff --git a/lib/Command/Db/RemoveUniqueIndices.php b/lib/Command/Db/RemoveUniqueIndices.php index fd3cc4274b..833e196061 100644 --- a/lib/Command/Db/RemoveUniqueIndices.php +++ b/lib/Command/Db/RemoveUniqueIndices.php @@ -10,7 +10,7 @@ use Doctrine\DBAL\Schema\Schema; use OCA\Polls\Command\Command; -use OCA\Polls\Db\V6\IndexManager; +use OCA\Polls\Db\V7\IndexManager; use OCP\IDBConnection; /** diff --git a/lib/Command/Db/ResetWatch.php b/lib/Command/Db/ResetWatch.php index a5a23aa376..c330dda642 100644 --- a/lib/Command/Db/ResetWatch.php +++ b/lib/Command/Db/ResetWatch.php @@ -10,10 +10,10 @@ use Doctrine\DBAL\Schema\Schema; use OCA\Polls\Command\Command; -use OCA\Polls\Db\V6\IndexManager; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\IndexManager; +use OCA\Polls\Db\V7\TableManager; use OCA\Polls\Db\Watch; -use OCA\Polls\Migration\V6\TableSchema; +use OCA\Polls\Migration\V7\TableSchema; use OCP\IDBConnection; /** diff --git a/lib/Cron/JanitorCron.php b/lib/Cron/JanitorCron.php index 57a6476bb9..f4ceb88b94 100644 --- a/lib/Cron/JanitorCron.php +++ b/lib/Cron/JanitorCron.php @@ -16,7 +16,7 @@ use OCA\Polls\Db\OptionMapper; use OCA\Polls\Db\PollMapper; use OCA\Polls\Db\ShareMapper; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCA\Polls\Db\VoteMapper; use OCA\Polls\Model\Settings\AppSettings; use OCP\AppFramework\Utility\ITimeFactory; diff --git a/lib/Db/V6/DbManager.php b/lib/Db/V7/DbManager.php similarity index 99% rename from lib/Db/V6/DbManager.php rename to lib/Db/V7/DbManager.php index 37444731d8..666f304410 100644 --- a/lib/Db/V6/DbManager.php +++ b/lib/Db/V7/DbManager.php @@ -6,7 +6,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace OCA\Polls\Db\V6; +namespace OCA\Polls\Db\V7; use Doctrine\DBAL\Schema\Schema; use Exception; diff --git a/lib/Db/V6/IndexManager.php b/lib/Db/V7/IndexManager.php similarity index 82% rename from lib/Db/V6/IndexManager.php rename to lib/Db/V7/IndexManager.php index 597e103800..29192c99cc 100644 --- a/lib/Db/V6/IndexManager.php +++ b/lib/Db/V7/IndexManager.php @@ -6,11 +6,11 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace OCA\Polls\Db\V6; +namespace OCA\Polls\Db\V7; use Doctrine\DBAL\Schema\Exception\IndexDoesNotExist; use Exception; -use OCA\Polls\Migration\V6\TableSchema; +use OCA\Polls\Migration\V7\TableSchema; use OCP\IConfig; use OCP\IDBConnection; use Psr\Log\LoggerInterface; @@ -27,6 +27,12 @@ public function __construct( parent::__construct($config, $connection, $logger); } + private function columnsMatch(array $existing, array $expected): bool { + sort($existing); + sort($expected); + return $existing === $expected; + } + /** * Create unique indices * Unique indices are crucial for the correct operation of the polls app. @@ -36,10 +42,44 @@ public function __construct( */ public function createUniqueIndices(): array { $messages = []; + $this->needsSchema(); foreach (TableSchema::UNIQUE_INDICES as $tableName => $uniqueIndices) { + $prefixedTable = $this->getTableName($tableName); + + if (!$this->schema->hasTable($prefixedTable)) { + continue; + } + + $table = $this->schema->getTable($prefixedTable); + foreach ($uniqueIndices as $name => $definition) { - $messages[] = $this->createIndex($tableName, $name, $definition['columns'], true); + $targetColumns = $definition['columns']; + $existsByName = $table->hasIndex($name); + $definitionMatches = $existsByName && $this->columnsMatch($table->getIndex($name)->getColumns(), $targetColumns); + + // 1+2: correct name, correct columns → skip + if ($existsByName && $definitionMatches) { + $messages[] = 'Unique index ' . $name . ' already exists in ' . $tableName; + continue; + } + + // 1 true, 2 false: correct name, wrong columns → drop and recreate + if ($existsByName) { + $table->dropIndex($name); + $messages[] = 'Dropped unique index ' . $name . ' from ' . $tableName . ' (definition mismatch)'; + } else { + // 1 false, 3: different name, same columns → drop and recreate with correct name + foreach ($table->getIndexes() as $index) { + if ($index->isUnique() && $this->columnsMatch($index->getColumns(), $targetColumns)) { + $messages[] = 'Dropped unique index ' . $index->getName() . ' from ' . $tableName . ' (renamed to ' . $name . ')'; + $table->dropIndex($index->getName()); + break; + } + } + } + + $messages[] = $this->createIndex($tableName, $name, $targetColumns, true); } } return $messages; @@ -98,6 +138,15 @@ public function createForeignKeyConstraint(string $parentTableName, string $chil $parentTable = $this->schema->getTable($parentTableName); $childTable = $this->schema->getTable($childTableName); + foreach ($childTable->getForeignKeys() as $fk) { + if ($fk->getForeignTableName() === $parentTableName + && $fk->getLocalColumns() === [$constraintColumn] + && $fk->getForeignColumns() === ['id'] + ) { + return 'Foreign key ' . $childTableName . '[' . $constraintColumn . '] -> ' . $parentTableName . '[id] already exists'; + } + } + $childTable->addForeignKeyConstraint($parentTable, [$constraintColumn], ['id'], ['onDelete' => 'CASCADE']); return 'Added ' . $parentTableName . '[' . $constraintColumn . '] <- ' . $childTableName . '[id]'; } diff --git a/lib/Db/V6/TableManager.php b/lib/Db/V7/TableManager.php similarity index 98% rename from lib/Db/V6/TableManager.php rename to lib/Db/V7/TableManager.php index 1c64023cca..d7cabb42ed 100644 --- a/lib/Db/V6/TableManager.php +++ b/lib/Db/V7/TableManager.php @@ -6,7 +6,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace OCA\Polls\Db\V6; +namespace OCA\Polls\Db\V7; use Doctrine\DBAL\Types\Type; use Exception; @@ -20,7 +20,7 @@ use OCA\Polls\Db\Watch; use OCA\Polls\Exceptions\PreconditionException; use OCA\Polls\Helper\Hash; -use OCA\Polls\Migration\V6\TableSchema; +use OCA\Polls\Migration\V7\TableSchema; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IConfig; use OCP\IDBConnection; @@ -416,6 +416,11 @@ private function deleteDuplicates(string $table, array $columns):int { $i = 0; foreach ($columns as $column) { + if (!$this->schema->getTable($this->dbPrefix . $table)->hasColumn($column)) { + $this->logger->warning('Column {column} does not exist in table {table} - cannot check for duplicates based on this column', ['column' => $column, 'table' => $this->dbPrefix . $table]); + return 0; + } + if ($i > 0) { $selection->andWhere($qb->expr()->eq('t1.' . $column, 't2.' . $column)); } else { diff --git a/lib/Listener/AddMissingIndicesListener.php b/lib/Listener/AddMissingIndicesListener.php index 15f6c003a9..4f7e7b74d9 100644 --- a/lib/Listener/AddMissingIndicesListener.php +++ b/lib/Listener/AddMissingIndicesListener.php @@ -8,7 +8,7 @@ namespace OCA\Polls\Listener; -use OCA\Polls\Migration\V6\TableSchema; +use OCA\Polls\Migration\V7\TableSchema; use OCP\DB\Events\AddMissingIndicesEvent; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; diff --git a/lib/Migration/FixVotes.php b/lib/Migration/FixVotes.php index 55155cdb6f..98d75023f7 100644 --- a/lib/Migration/FixVotes.php +++ b/lib/Migration/FixVotes.php @@ -10,7 +10,7 @@ namespace OCA\Polls\Migration; use Doctrine\DBAL\Schema\Schema; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCP\IDBConnection; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/Migration/RepairSteps/CleanTables.php b/lib/Migration/RepairSteps/CleanTables.php index f8ed071318..a871427c0e 100644 --- a/lib/Migration/RepairSteps/CleanTables.php +++ b/lib/Migration/RepairSteps/CleanTables.php @@ -12,7 +12,7 @@ use Doctrine\DBAL\Schema\Schema; use Exception; use OCA\Polls\Db\Poll; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCP\IDBConnection; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/Migration/RepairSteps/CreateIndices.php b/lib/Migration/RepairSteps/CreateIndices.php index 5bb00368df..a03eb96709 100644 --- a/lib/Migration/RepairSteps/CreateIndices.php +++ b/lib/Migration/RepairSteps/CreateIndices.php @@ -11,7 +11,7 @@ use Doctrine\DBAL\Schema\Schema; use OCA\Polls\Db\Share; -use OCA\Polls\Db\V6\IndexManager; +use OCA\Polls\Db\V7\IndexManager; use OCP\IDBConnection; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/Migration/RepairSteps/CreateTables.php b/lib/Migration/RepairSteps/CreateTables.php index 2623c882df..5013f270aa 100644 --- a/lib/Migration/RepairSteps/CreateTables.php +++ b/lib/Migration/RepairSteps/CreateTables.php @@ -10,7 +10,7 @@ namespace OCA\Polls\Migration\RepairSteps; use Doctrine\DBAL\Schema\Schema; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCP\IDBConnection; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/Migration/RepairSteps/DropOrphanedColumns.php b/lib/Migration/RepairSteps/DropOrphanedColumns.php index 1960d2ea11..c28fb9b5c4 100644 --- a/lib/Migration/RepairSteps/DropOrphanedColumns.php +++ b/lib/Migration/RepairSteps/DropOrphanedColumns.php @@ -10,7 +10,7 @@ namespace OCA\Polls\Migration\RepairSteps; use Doctrine\DBAL\Schema\Schema; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCP\IDBConnection; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/Migration/RepairSteps/DropOrphanedTables.php b/lib/Migration/RepairSteps/DropOrphanedTables.php index cb1d8f502d..95bcbdac29 100644 --- a/lib/Migration/RepairSteps/DropOrphanedTables.php +++ b/lib/Migration/RepairSteps/DropOrphanedTables.php @@ -10,7 +10,7 @@ namespace OCA\Polls\Migration\RepairSteps; use Doctrine\DBAL\Schema\Schema; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCP\IDBConnection; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/Migration/RepairSteps/FixNullish.php b/lib/Migration/RepairSteps/FixNullish.php index c02c3172fd..974d1d1edc 100644 --- a/lib/Migration/RepairSteps/FixNullish.php +++ b/lib/Migration/RepairSteps/FixNullish.php @@ -9,7 +9,7 @@ namespace OCA\Polls\Migration\RepairSteps; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCP\IDBConnection; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/Migration/RepairSteps/Install.php b/lib/Migration/RepairSteps/Install.php index 322fea6ce8..7ca34fa6a6 100644 --- a/lib/Migration/RepairSteps/Install.php +++ b/lib/Migration/RepairSteps/Install.php @@ -10,7 +10,7 @@ namespace OCA\Polls\Migration\RepairSteps; use Doctrine\DBAL\Schema\Schema; -use OCA\Polls\Db\V6\IndexManager; +use OCA\Polls\Db\V7\IndexManager; use OCP\IDBConnection; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/Migration/RepairSteps/MigratePublicToOpen.php b/lib/Migration/RepairSteps/MigratePublicToOpen.php index d0a9f510a0..4aa89abcbc 100644 --- a/lib/Migration/RepairSteps/MigratePublicToOpen.php +++ b/lib/Migration/RepairSteps/MigratePublicToOpen.php @@ -9,7 +9,7 @@ namespace OCA\Polls\Migration\RepairSteps; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCP\IDBConnection; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/Migration/RepairSteps/RemoveIndices.php b/lib/Migration/RepairSteps/RemoveIndices.php index 2eed694796..b82a289de7 100644 --- a/lib/Migration/RepairSteps/RemoveIndices.php +++ b/lib/Migration/RepairSteps/RemoveIndices.php @@ -9,7 +9,7 @@ namespace OCA\Polls\Migration\RepairSteps; use Doctrine\DBAL\Schema\Schema; -use OCA\Polls\Db\V6\IndexManager; +use OCA\Polls\Db\V7\IndexManager; use OCP\IDBConnection; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/Migration/RepairSteps/RemoveObsoleteMigrations.php b/lib/Migration/RepairSteps/RemoveObsoleteMigrations.php index 1a1d821dea..424f56f703 100644 --- a/lib/Migration/RepairSteps/RemoveObsoleteMigrations.php +++ b/lib/Migration/RepairSteps/RemoveObsoleteMigrations.php @@ -9,7 +9,7 @@ namespace OCA\Polls\Migration\RepairSteps; use Doctrine\DBAL\Schema\Schema; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCP\IDBConnection; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/Migration/RepairSteps/SetLastInteraction.php b/lib/Migration/RepairSteps/SetLastInteraction.php index 5a407ce29d..50b1b8709d 100644 --- a/lib/Migration/RepairSteps/SetLastInteraction.php +++ b/lib/Migration/RepairSteps/SetLastInteraction.php @@ -9,7 +9,7 @@ namespace OCA\Polls\Migration\RepairSteps; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCA\Polls\Db\WatchMapper; use OCP\IDBConnection; use OCP\Migration\IOutput; diff --git a/lib/Migration/RepairSteps/UpdateHashes.php b/lib/Migration/RepairSteps/UpdateHashes.php index 6ead8b3346..7c9802755b 100644 --- a/lib/Migration/RepairSteps/UpdateHashes.php +++ b/lib/Migration/RepairSteps/UpdateHashes.php @@ -9,7 +9,7 @@ namespace OCA\Polls\Migration\RepairSteps; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCP\IDBConnection; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/Migration/RepairSteps/UpdateInteraction.php b/lib/Migration/RepairSteps/UpdateInteraction.php index d63adb2c2b..790d620cd7 100644 --- a/lib/Migration/RepairSteps/UpdateInteraction.php +++ b/lib/Migration/RepairSteps/UpdateInteraction.php @@ -9,7 +9,7 @@ namespace OCA\Polls\Migration\RepairSteps; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\TableManager; use OCP\IDBConnection; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; diff --git a/lib/Migration/V6/TableSchema.php b/lib/Migration/V7/TableSchema.php similarity index 99% rename from lib/Migration/V6/TableSchema.php rename to lib/Migration/V7/TableSchema.php index ac21f363f0..518e09803e 100644 --- a/lib/Migration/V6/TableSchema.php +++ b/lib/Migration/V7/TableSchema.php @@ -6,7 +6,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace OCA\Polls\Migration\V6; +namespace OCA\Polls\Migration\V7; use OCA\Polls\Db\Comment; use OCA\Polls\Db\Log; diff --git a/lib/Migration/Version080301Date20250822153002.php b/lib/Migration/Version080301Date20250822153002.php index abaa299611..b2dd2a3630 100644 --- a/lib/Migration/Version080301Date20250822153002.php +++ b/lib/Migration/Version080301Date20250822153002.php @@ -8,8 +8,8 @@ namespace OCA\Polls\Migration; -use OCA\Polls\Db\V6\IndexManager; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\IndexManager; +use OCA\Polls\Db\V7\TableManager; use OCP\DB\ISchemaWrapper; use OCP\IDBConnection; use OCP\Migration\IOutput; diff --git a/lib/Migration/Version080307Date20250826231102.php b/lib/Migration/Version080307Date20250826231102.php index b10300348c..fe89a2f523 100644 --- a/lib/Migration/Version080307Date20250826231102.php +++ b/lib/Migration/Version080307Date20250826231102.php @@ -9,8 +9,8 @@ namespace OCA\Polls\Migration; use OCA\Polls\Db\Share; -use OCA\Polls\Db\V6\IndexManager; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\IndexManager; +use OCA\Polls\Db\V7\TableManager; use OCP\DB\ISchemaWrapper; use OCP\IDBConnection; use OCP\Migration\IOutput; diff --git a/lib/Migration/Version090000Date20260302212000.php b/lib/Migration/Version090000Date20260302212000.php index 0c8ac71e76..fa952b7e91 100644 --- a/lib/Migration/Version090000Date20260302212000.php +++ b/lib/Migration/Version090000Date20260302212000.php @@ -8,8 +8,8 @@ namespace OCA\Polls\Migration; -use OCA\Polls\Db\V6\IndexManager; -use OCA\Polls\Db\V6\TableManager; +use OCA\Polls\Db\V7\IndexManager; +use OCA\Polls\Db\V7\TableManager; use OCP\DB\ISchemaWrapper; use OCP\IDBConnection; use OCP\Migration\IOutput;