Skip to content

Commit 83f7ea0

Browse files
authored
Merge pull request #39396 from nextcloud/backport/39389/stable27
2 parents 31f07f3 + 18db96c commit 83f7ea0

8 files changed

Lines changed: 128 additions & 5 deletions

File tree

apps/settings/lib/Controller/CheckSetupController.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@
7272
use OCP\AppFramework\Http\DataDisplayResponse;
7373
use OCP\AppFramework\Http\DataResponse;
7474
use OCP\AppFramework\Http\RedirectResponse;
75+
use OCP\DB\Events\AddMissingIndicesEvent;
7576
use OCP\DB\Types;
77+
use OCP\EventDispatcher\IEventDispatcher;
7678
use OCP\Http\Client\IClientService;
7779
use OCP\IConfig;
7880
use OCP\IDateTimeFormatter;
@@ -102,6 +104,8 @@ class CheckSetupController extends Controller {
102104
private $checker;
103105
/** @var LoggerInterface */
104106
private $logger;
107+
/** @var IEventDispatcher */
108+
private $eventDispatcher;
105109
/** @var EventDispatcherInterface */
106110
private $dispatcher;
107111
/** @var Connection */
@@ -135,6 +139,7 @@ public function __construct($AppName,
135139
IL10N $l10n,
136140
Checker $checker,
137141
LoggerInterface $logger,
142+
IEventDispatcher $eventDispatcher,
138143
EventDispatcherInterface $dispatcher,
139144
Connection $db,
140145
ILockingProvider $lockingProvider,
@@ -155,6 +160,7 @@ public function __construct($AppName,
155160
$this->l10n = $l10n;
156161
$this->checker = $checker;
157162
$this->logger = $logger;
163+
$this->eventDispatcher = $eventDispatcher;
158164
$this->dispatcher = $dispatcher;
159165
$this->db = $db;
160166
$this->lockingProvider = $lockingProvider;
@@ -551,10 +557,27 @@ protected function hasFreeTypeSupport() {
551557

552558
protected function hasMissingIndexes(): array {
553559
$indexInfo = new MissingIndexInformation();
560+
554561
// Dispatch event so apps can also hint for pending index updates if needed
555562
$event = new GenericEvent($indexInfo);
556563
$this->dispatcher->dispatch(IDBConnection::CHECK_MISSING_INDEXES_EVENT, $event);
557564

565+
$event = new AddMissingIndicesEvent();
566+
$this->eventDispatcher->dispatchTyped($event);
567+
$missingIndices = $event->getMissingIndices();
568+
569+
if ($missingIndices !== []) {
570+
$schema = new SchemaWrapper(\OCP\Server::get(Connection::class));
571+
foreach ($missingIndices as $missingIndex) {
572+
if ($schema->hasTable($missingIndex['tableName'])) {
573+
$table = $schema->getTable($missingIndex['tableName']);
574+
if (!$table->hasIndex($missingIndex['indexName'])) {
575+
$indexInfo->addHintForMissingSubject($missingIndex['tableName'], $missingIndex['indexName']);
576+
}
577+
}
578+
}
579+
}
580+
558581
return $indexInfo->getListOfMissingIndexes();
559582
}
560583

apps/settings/tests/Controller/CheckSetupControllerTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
use OCP\AppFramework\Http\DataDisplayResponse;
4848
use OCP\AppFramework\Http\DataResponse;
4949
use OCP\AppFramework\Http\RedirectResponse;
50+
use OCP\EventDispatcher\IEventDispatcher;
5051
use OCP\Http\Client\IClientService;
5152
use OCP\IConfig;
5253
use OCP\IDateTimeFormatter;
@@ -87,6 +88,8 @@ class CheckSetupControllerTest extends TestCase {
8788
private $logger;
8889
/** @var Checker|\PHPUnit\Framework\MockObject\MockObject */
8990
private $checker;
91+
/** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */
92+
private $eventDispatcher;
9093
/** @var EventDispatcherInterface|\PHPUnit\Framework\MockObject\MockObject */
9194
private $dispatcher;
9295
/** @var Connection|\PHPUnit\Framework\MockObject\MockObject */
@@ -137,6 +140,7 @@ protected function setUp(): void {
137140
->willReturnCallback(function ($message, array $replace) {
138141
return vsprintf($message, $replace);
139142
});
143+
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
140144
$this->dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)
141145
->disableOriginalConstructor()->getMock();
142146
$this->checker = $this->getMockBuilder('\OC\IntegrityCheck\Checker')
@@ -167,6 +171,7 @@ protected function setUp(): void {
167171
$this->l10n,
168172
$this->checker,
169173
$this->logger,
174+
$this->eventDispatcher,
170175
$this->dispatcher,
171176
$this->db,
172177
$this->lockingProvider,
@@ -676,6 +681,7 @@ public function testGetCurlVersion() {
676681
$this->l10n,
677682
$this->checker,
678683
$this->logger,
684+
$this->eventDispatcher,
679685
$this->dispatcher,
680686
$this->db,
681687
$this->lockingProvider,
@@ -1440,6 +1446,7 @@ public function testIsMysqlUsedWithoutUTF8MB4(string $db, bool $useUTF8MB4, bool
14401446
$this->l10n,
14411447
$this->checker,
14421448
$this->logger,
1449+
$this->eventDispatcher,
14431450
$this->dispatcher,
14441451
$this->db,
14451452
$this->lockingProvider,
@@ -1494,6 +1501,7 @@ public function testIsEnoughTempSpaceAvailableIfS3PrimaryStorageIsUsed(string $m
14941501
$this->l10n,
14951502
$this->checker,
14961503
$this->logger,
1504+
$this->eventDispatcher,
14971505
$this->dispatcher,
14981506
$this->db,
14991507
$this->lockingProvider,

core/Command/Db/AddMissingIndices.php

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
use Doctrine\DBAL\Platforms\PostgreSQL94Platform;
3737
use OC\DB\Connection;
3838
use OC\DB\SchemaWrapper;
39+
use OCP\DB\Events\AddMissingIndicesEvent;
40+
use OCP\EventDispatcher\IEventDispatcher;
3941
use OCP\IDBConnection;
4042
use Symfony\Component\Console\Command\Command;
4143
use Symfony\Component\Console\Input\InputOption;
@@ -54,12 +56,14 @@
5456
*/
5557
class AddMissingIndices extends Command {
5658
private Connection $connection;
59+
private IEventDispatcher $eventDispatcher;
5760
private EventDispatcherInterface $dispatcher;
5861

59-
public function __construct(Connection $connection, EventDispatcherInterface $dispatcher) {
62+
public function __construct(Connection $connection, IEventDispatcher $eventDispatcher, EventDispatcherInterface $dispatcher) {
6063
parent::__construct();
6164

6265
$this->connection = $connection;
66+
$this->eventDispatcher = $eventDispatcher;
6367
$this->dispatcher = $dispatcher;
6468
}
6569

@@ -71,11 +75,37 @@ protected function configure() {
7175
}
7276

7377
protected function execute(InputInterface $input, OutputInterface $output): int {
74-
$this->addCoreIndexes($output, $input->getOption('dry-run'));
78+
$dryRun = $input->getOption('dry-run');
79+
80+
$this->addCoreIndexes($output, $dryRun);
7581

7682
// Dispatch event so apps can also update indexes if needed
7783
$event = new GenericEvent($output);
7884
$this->dispatcher->dispatch(IDBConnection::ADD_MISSING_INDEXES_EVENT, $event);
85+
86+
$event = new AddMissingIndicesEvent();
87+
$this->eventDispatcher->dispatchTyped($event);
88+
89+
$missingIndices = $event->getMissingIndices();
90+
if ($missingIndices !== []) {
91+
$schema = new SchemaWrapper($this->connection);
92+
93+
foreach ($missingIndices as $missingIndex) {
94+
if ($schema->hasTable($missingIndex['tableName'])) {
95+
$table = $schema->getTable($missingIndex['tableName']);
96+
if (!$table->hasIndex($missingIndex['indexName'])) {
97+
$output->writeln('<info>Adding additional ' . $missingIndex['indexName'] . ' index to the ' . $table->getName() . ' table, this can take some time...</info>');
98+
$table->addIndex($missingIndex['columns'], $missingIndex['indexName']);
99+
$sqlQueries = $this->connection->migrateToSchema($schema->getWrappedSchema(), $dryRun);
100+
if ($dryRun && $sqlQueries !== null) {
101+
$output->writeln($sqlQueries);
102+
}
103+
$output->writeln('<info>' . $table->getName() . ' table updated successfully.</info>');
104+
}
105+
}
106+
}
107+
}
108+
79109
return 0;
80110
}
81111

core/register_command.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@
109109
$application->add(new OC\Core\Command\Db\ConvertType(\OC::$server->getConfig(), new \OC\DB\ConnectionFactory(\OC::$server->getSystemConfig())));
110110
$application->add(new OC\Core\Command\Db\ConvertMysqlToMB4(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection(), \OC::$server->getURLGenerator(), \OC::$server->get(LoggerInterface::class)));
111111
$application->add(new OC\Core\Command\Db\ConvertFilecacheBigInt(\OC::$server->get(\OC\DB\Connection::class)));
112-
$application->add(new OC\Core\Command\Db\AddMissingIndices(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getEventDispatcher()));
112+
$application->add(\OCP\Server::get(\OC\Core\Command\Db\AddMissingIndices::class));
113113
$application->add(new OC\Core\Command\Db\AddMissingColumns(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getEventDispatcher()));
114114
$application->add(new OC\Core\Command\Db\AddMissingPrimaryKeys(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getEventDispatcher()));
115115

lib/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@
202202
'OCP\\Contacts\\ContactsMenu\\IProvider' => $baseDir . '/lib/public/Contacts/ContactsMenu/IProvider.php',
203203
'OCP\\Contacts\\Events\\ContactInteractedWithEvent' => $baseDir . '/lib/public/Contacts/Events/ContactInteractedWithEvent.php',
204204
'OCP\\Contacts\\IManager' => $baseDir . '/lib/public/Contacts/IManager.php',
205+
'OCP\\DB\\Events\\AddMissingIndicesEvent' => $baseDir . '/lib/public/DB/Events/AddMissingIndicesEvent.php',
205206
'OCP\\DB\\Exception' => $baseDir . '/lib/public/DB/Exception.php',
206207
'OCP\\DB\\IPreparedStatement' => $baseDir . '/lib/public/DB/IPreparedStatement.php',
207208
'OCP\\DB\\IResult' => $baseDir . '/lib/public/DB/IResult.php',

lib/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
235235
'OCP\\Contacts\\ContactsMenu\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IProvider.php',
236236
'OCP\\Contacts\\Events\\ContactInteractedWithEvent' => __DIR__ . '/../../..' . '/lib/public/Contacts/Events/ContactInteractedWithEvent.php',
237237
'OCP\\Contacts\\IManager' => __DIR__ . '/../../..' . '/lib/public/Contacts/IManager.php',
238+
'OCP\\DB\\Events\\AddMissingIndicesEvent' => __DIR__ . '/../../..' . '/lib/public/DB/Events/AddMissingIndicesEvent.php',
238239
'OCP\\DB\\Exception' => __DIR__ . '/../../..' . '/lib/public/DB/Exception.php',
239240
'OCP\\DB\\IPreparedStatement' => __DIR__ . '/../../..' . '/lib/public/DB/IPreparedStatement.php',
240241
'OCP\\DB\\IResult' => __DIR__ . '/../../..' . '/lib/public/DB/IResult.php',
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* @copyright Copyright (c) 2023 Julius Härtl <jus@bitgrid.net
6+
*
7+
* @author Julius Härtl <jus@bitgrid.net
8+
*
9+
* @license GNU AGPL version 3 or any later version
10+
*
11+
* This program is free software: you can redistribute it and/or modify
12+
* it under the terms of the GNU Affero General Public License as
13+
* published by the Free Software Foundation, either version 3 of the
14+
* License, or (at your option) any later version.
15+
*
16+
* This program is distributed in the hope that it will be useful,
17+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
* GNU Affero General Public License for more details.
20+
*
21+
* You should have received a copy of the GNU Affero General Public License
22+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
23+
*
24+
*/
25+
26+
namespace OCP\DB\Events;
27+
28+
/**
29+
* Event to allow apps to register information about missing database indices
30+
*
31+
* This event will be dispatched for checking on the admin settings and when running
32+
* occ db:add-missing-indices which will then create those indices
33+
*
34+
* @since 28.0.0
35+
*/
36+
class AddMissingIndicesEvent extends \OCP\EventDispatcher\Event {
37+
/** @var array<array-key, array{tableName: string, indexName: string, columns: string[]}> */
38+
private array $missingIndices = [];
39+
40+
/**
41+
* @param string[] $columns
42+
* @since 28.0.0
43+
*/
44+
public function addMissingIndex(string $tableName, string $indexName, array $columns): void {
45+
$this->missingIndices[] = [
46+
'tableName' => $tableName,
47+
'indexName' => $indexName,
48+
'columns' => $columns
49+
];
50+
}
51+
52+
/**
53+
* @since 28.0.0
54+
* @return array<array-key, array{tableName: string, indexName: string, columns: string[]}>
55+
*/
56+
public function getMissingIndices(): array {
57+
return $this->missingIndices;
58+
}
59+
}

lib/public/IDBConnection.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
namespace OCP;
3535

3636
use Doctrine\DBAL\Schema\Schema;
37+
use OCP\DB\Events\AddMissingIndicesEvent;
3738
use OCP\DB\Exception;
3839
use OCP\DB\IPreparedStatement;
3940
use OCP\DB\IResult;
@@ -46,12 +47,12 @@
4647
*/
4748
interface IDBConnection {
4849
/**
49-
* @deprecated 22.0.0 this is an internal event
50+
* @deprecated 22.0.0 this is an internal event, use {@see AddMissingIndicesEvent} instead
5051
*/
5152
public const ADD_MISSING_INDEXES_EVENT = self::class . '::ADD_MISSING_INDEXES';
5253

5354
/**
54-
* @deprecated 22.0.0 this is an internal event
55+
* @deprecated 22.0.0 this is an internal event, use {@see AddMissingIndicesEvent} instead
5556
*/
5657
public const CHECK_MISSING_INDEXES_EVENT = self::class . '::CHECK_MISSING_INDEXES';
5758

0 commit comments

Comments
 (0)