Skip to content

Commit 1ceb1c6

Browse files
committed
fix(db): drop index on mail_mailboxes by columns instead of name
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
1 parent f1b7ac4 commit 1ceb1c6

File tree

4 files changed

+103
-17
lines changed

4 files changed

+103
-17
lines changed

lib/Migration/Version3500Date20231115184458.php

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,28 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
2828

2929
$mailboxesTable = $schema->getTable('mail_mailboxes');
3030

31-
$indexNew = 'mail_mb_account_id_name_hash';
32-
3331
/**
34-
* Variant 1 - with table prefix
32+
* The migration "Version0161Date20190902103701" created a unique index for account_id and name without
33+
* specifying a name. Unfortunately, this resulted in different index names depending on the table
34+
* prefix, which means we now have to loop through the indexes to find the correct one.
35+
*
36+
* This migration is from 2023-11 and, by now, most people should already have it. Although it is not
37+
* recommended to change migrations after they have been released, we are still updating this
38+
* one for correctness as it was supposed to drop the index here.
39+
*
40+
* On newer versions, this will be a no-op, as creating the index
41+
* in "Version0161Date20190902103701" is commented out.
42+
*
43+
* @see \OCA\Mail\Migration\Version0161Date20190902103701::changeSchema
3544
*/
36-
if ($mailboxesTable->hasIndex('UNIQ_22DEBD839B6B5FBA5E237E06')) {
37-
$mailboxesTable->dropIndex('UNIQ_22DEBD839B6B5FBA5E237E06');
38-
}
39-
/**
40-
* Variant 2 - without table prefix
41-
* @see \OCA\Mail\Migration\Version5006Date20250927130132::changeSchema
42-
*/
43-
if ($mailboxesTable->hasIndex('UNIQ_45754FF89B6B5FBA5E237E06')) {
44-
$mailboxesTable->dropIndex('UNIQ_45754FF89B6B5FBA5E237E06');
45+
foreach ($mailboxesTable->getIndexes() as $index) {
46+
if ($index->isUnique() && $index->spansColumns(['account_id', 'name'])) {
47+
$mailboxesTable->dropIndex($index->getName());
48+
}
4549
}
4650

51+
$indexNew = 'mail_mb_account_id_name_hash';
52+
4753
if (!$mailboxesTable->hasIndex($indexNew)) {
4854
$mailboxesTable->addUniqueIndex(['account_id', 'name_hash'], $indexNew);
4955
}

lib/Migration/Version5006Date20250927130132.php

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,33 @@
2020
#[ModifyColumn(table: 'mail_mailboxes', name: 'name', type: ColumnType::STRING, description: 'Increase the column length from 255 to 1024')]
2121
class Version5006Date20250927130132 extends SimpleMigrationStep {
2222

23+
/**
24+
* @psalm-param Closure():ISchemaWrapper $schemaClosure
25+
*/
2326
#[Override]
2427
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
2528
$schema = $schemaClosure();
2629

2730
$mailboxes = $schema->getTable('mail_mailboxes');
2831

2932
/**
30-
* Make sure the old account_id+name index is gone. The DB won't allow
31-
* the name length increase otherwise
33+
* The migration "Version0161Date20190902103701" created a unique index for account_id and name without
34+
* specifying a name. Unfortunately, this resulted in different index names depending on the table
35+
* prefix, which means we now have to loop through the indexes to find the correct one.
3236
*
37+
* The index on account_id and name were supposed to be dropped in "Version3500Date20231115184458",
38+
* but this did not work on every setup due to the name mismatch caused by different table prefixes.
39+
*
40+
* Although it is not recommended to change migrations after release,
41+
* we are updating this one with a safeguard to drop any existing index on account_id and name.
42+
*
43+
* @see \OCA\Mail\Migration\Version0161Date20190902103701::changeSchema
3344
* @see \OCA\Mail\Migration\Version3500Date20231115184458::changeSchema
3445
*/
35-
if ($mailboxes->hasIndex('UNIQ_45754FF89B6B5FBA5E237E06')) {
36-
$mailboxes->dropIndex('UNIQ_45754FF89B6B5FBA5E237E06');
46+
foreach ($mailboxes->getIndexes() as $index) {
47+
if ($index->isUnique() && $index->spansColumns(['account_id', 'name'])) {
48+
$mailboxes->dropIndex($index->getName());
49+
}
3750
}
3851

3952
$mailboxes->modifyColumn(

lib/Migration/Version5006Date20251015082003.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,16 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
2828
$schema = $schemaClosure();
2929

3030
/**
31-
* Make sure the old account_id+name index is gone for good
31+
* The migration "Version0161Date20190902103701" created a unique index for account_id and name without
32+
* specifying a name. Unfortunately, this resulted in different index names depending on the table
33+
* prefix, which means we now have to loop through the indexes to find the correct one.
3234
*
35+
* The index on account_id and name were supposed to be dropped in "Version3500Date20231115184458",
36+
* but this did not work on every setup due to the name mismatch caused by different table prefixes.
37+
*
38+
* @see \OCA\Mail\Migration\Version0161Date20190902103701::changeSchema
3339
* @see \OCA\Mail\Migration\Version3500Date20231115184458::changeSchema
40+
* @see \OCA\Mail\Migration\Version5006Date20250927130132::changeSchema
3441
*/
3542
$mailboxesTable = $schema->getTable('mail_mailboxes');
3643
if (!$mailboxesTable->hasIndex('UNIQ_45754FF89B6B5FBA5E237E06')) {
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Mail\Migration;
11+
12+
use Closure;
13+
use OCP\DB\ISchemaWrapper;
14+
use OCP\Migration\IOutput;
15+
use OCP\Migration\SimpleMigrationStep;
16+
use Override;
17+
18+
class Version5006Date20251023191023 extends SimpleMigrationStep {
19+
20+
/**
21+
* @param Closure(): ISchemaWrapper $schemaClosure
22+
*/
23+
#[Override]
24+
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
25+
$schema = $schemaClosure();
26+
27+
$mailboxes = $schema->getTable('mail_mailboxes');
28+
29+
/**
30+
* The migration "Version0161Date20190902103701" created a unique index for account_id and name without
31+
* specifying a name. Unfortunately, this resulted in different index names depending on the table
32+
* prefix, which means we now have to loop through the indexes to find the correct one.
33+
*
34+
* The index on account_id and name were supposed to be dropped in "Version3500Date20231115184458",
35+
* but this did not work on every setup due to the name mismatch caused by different table prefixes.
36+
*
37+
* On MySQL or MariaDB versions before 10.5, changing the length of the name column to 1024 fails if the
38+
* index on account_id and name still exists, with the error "Specified key was too long; max key length is 3072 bytes."
39+
* However, this change works on MariaDB 10.5 or newer.
40+
*
41+
* The reason is that MariaDB automatically converts a unique index using btree to hash if the key exceeds
42+
* the maximum length and is supported by the storage engine: https://mariadb.com/docs/server/mariadb-quickstart-guides/mariadb-indexes-guide#unique-index
43+
*
44+
* This means that on setups with a different table prefix using MariaDB 10.5, the index on account_id and name
45+
* might still exist. Since we don't need it, we will make another attempt to drop it here.
46+
*
47+
* @see \OCA\Mail\Migration\Version0161Date20190902103701::changeSchema
48+
* @see \OCA\Mail\Migration\Version3500Date20231115184458::changeSchema
49+
* @see \OCA\Mail\Migration\Version5006Date20250927130132::changeSchema
50+
* @see \OCA\Mail\Migration\Version5006Date20251015082003::changeSchema
51+
*/
52+
foreach ($mailboxes->getIndexes() as $index) {
53+
if ($index->isUnique() && $index->spansColumns(['account_id', 'name'])) {
54+
$mailboxes->dropIndex($index->getName());
55+
}
56+
}
57+
58+
return $schema;
59+
}
60+
}

0 commit comments

Comments
 (0)