Skip to content

Commit c88a5b4

Browse files
authored
Merge pull request #54519 from nextcloud/fix/fix-duplicated-category-migration
fix: Fix unique constraint violation in oc_vcategory migration
2 parents 7b82f13 + e2b8ef7 commit c88a5b4

File tree

1 file changed

+40
-1
lines changed

1 file changed

+40
-1
lines changed

core/Migrations/Version32000Date20250731062008.php

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $
4141
/**
4242
* Clean up duplicate categories
4343
*/
44-
private function cleanupDuplicateCategories(IOutput $output) {
44+
private function cleanupDuplicateCategories(IOutput $output): void {
4545
$output->info('Starting cleanup of duplicate vcategory records...');
4646

4747
// Find all categories, ordered to identify duplicates
@@ -74,6 +74,8 @@ private function cleanupDuplicateCategories(IOutput $output) {
7474

7575
$output->info("Found duplicate: keeping ID $keepId, removing ID $categoryId");
7676

77+
$this->cleanupDuplicateAssignments($output, $categoryId, $keepId);
78+
7779
// Update object references
7880
$updateQb = $this->connection->getQueryBuilder();
7981
$updateQb->update('vcategory_to_object')
@@ -103,4 +105,41 @@ private function cleanupDuplicateCategories(IOutput $output) {
103105
$output->info("Duplicate cleanup completed - processed $duplicateCount duplicates");
104106
}
105107
}
108+
109+
/**
110+
* Clean up duplicate assignments
111+
* That will delete rows with $categoryId when there is the same row with $keepId
112+
*/
113+
private function cleanupDuplicateAssignments(IOutput $output, int $categoryId, int $keepId): void {
114+
$selectQb = $this->connection->getQueryBuilder();
115+
$selectQb->select('o1.*')
116+
->from('vcategory_to_object', 'o1')
117+
->join(
118+
'o1', 'vcategory_to_object', 'o2',
119+
$selectQb->expr()->andX(
120+
$selectQb->expr()->eq('o1.type', 'o2.type'),
121+
$selectQb->expr()->eq('o1.objid', 'o2.objid'),
122+
)
123+
)
124+
->where($selectQb->expr()->eq('o1.categoryid', $selectQb->createNamedParameter($categoryId)))
125+
->andWhere($selectQb->expr()->eq('o2.categoryid', $selectQb->createNamedParameter($keepId)));
126+
127+
$deleteQb = $this->connection->getQueryBuilder();
128+
$deleteQb->delete('vcategory_to_object')
129+
->where($deleteQb->expr()->eq('objid', $deleteQb->createParameter('objid')))
130+
->andWhere($deleteQb->expr()->eq('categoryid', $deleteQb->createParameter('categoryid')))
131+
->andWhere($deleteQb->expr()->eq('type', $deleteQb->createParameter('type')));
132+
133+
$duplicatedAssignments = $selectQb->executeQuery();
134+
$count = 0;
135+
while ($row = $duplicatedAssignments->fetch()) {
136+
$deleteQb
137+
->setParameters($row)
138+
->executeStatement();
139+
$count++;
140+
}
141+
if ($count > 0) {
142+
$output->info(" - Deleted $count duplicate category assignments for $categoryId and $keepId");
143+
}
144+
}
106145
}

0 commit comments

Comments
 (0)