]> source.dussan.org Git - nextcloud-server.git/commitdiff
feat: Add public event for missing indices 39397/head
authorJulius Härtl <jus@bitgrid.net>
Fri, 14 Jul 2023 08:34:09 +0000 (10:34 +0200)
committerJulius Härtl <jus@bitgrid.net>
Fri, 14 Jul 2023 14:30:36 +0000 (16:30 +0200)
Signed-off-by: Julius Härtl <jus@bitgrid.net>
apps/settings/lib/Controller/CheckSetupController.php
apps/settings/tests/Controller/CheckSetupControllerTest.php
core/Command/Db/AddMissingIndices.php
core/register_command.php
lib/composer/composer/autoload_classmap.php
lib/composer/composer/autoload_static.php
lib/public/DB/Events/AddMissingIndicesEvent.php [new file with mode: 0644]
lib/public/IDBConnection.php

index a6f4d7a0d41f728e8d1b5fab83a1fb98d234ffd6..aee99310b6ac9c184a103dface01d4996b6ff71f 100644 (file)
@@ -71,7 +71,9 @@ use OCP\AppFramework\Controller;
 use OCP\AppFramework\Http\DataDisplayResponse;
 use OCP\AppFramework\Http\DataResponse;
 use OCP\AppFramework\Http\RedirectResponse;
+use OCP\DB\Events\AddMissingIndicesEvent;
 use OCP\DB\Types;
+use OCP\EventDispatcher\IEventDispatcher;
 use OCP\Http\Client\IClientService;
 use OCP\IConfig;
 use OCP\IDateTimeFormatter;
@@ -101,6 +103,8 @@ class CheckSetupController extends Controller {
        private $checker;
        /** @var LoggerInterface */
        private $logger;
+       /** @var IEventDispatcher */
+       private $eventDispatcher;
        /** @var EventDispatcherInterface */
        private $dispatcher;
        /** @var Connection */
@@ -134,6 +138,7 @@ class CheckSetupController extends Controller {
                                                                IL10N $l10n,
                                                                Checker $checker,
                                                                LoggerInterface $logger,
+                                                               IEventDispatcher $eventDispatcher,
                                                                EventDispatcherInterface $dispatcher,
                                                                Connection $db,
                                                                ILockingProvider $lockingProvider,
@@ -154,6 +159,7 @@ class CheckSetupController extends Controller {
                $this->l10n = $l10n;
                $this->checker = $checker;
                $this->logger = $logger;
+               $this->eventDispatcher = $eventDispatcher;
                $this->dispatcher = $dispatcher;
                $this->db = $db;
                $this->lockingProvider = $lockingProvider;
@@ -550,10 +556,27 @@ Raw output
 
        protected function hasMissingIndexes(): array {
                $indexInfo = new MissingIndexInformation();
+
                // Dispatch event so apps can also hint for pending index updates if needed
                $event = new GenericEvent($indexInfo);
                $this->dispatcher->dispatch(IDBConnection::CHECK_MISSING_INDEXES_EVENT, $event);
 
+               $event = new AddMissingIndicesEvent();
+               $this->eventDispatcher->dispatchTyped($event);
+               $missingIndices = $event->getMissingIndices();
+
+               if ($missingIndices !== []) {
+                       $schema = new SchemaWrapper(\OCP\Server::get(Connection::class));
+                       foreach ($missingIndices as $missingIndex) {
+                               if ($schema->hasTable($missingIndex['tableName'])) {
+                                       $table = $schema->getTable($missingIndex['tableName']);
+                                       if (!$table->hasIndex($missingIndex['indexName'])) {
+                                               $indexInfo->addHintForMissingSubject($missingIndex['tableName'], $missingIndex['indexName']);
+                                       }
+                               }
+                       }
+               }
+
                return $indexInfo->getListOfMissingIndexes();
        }
 
index 81aa7af0b21c53a0f47365956d55a68a0daa7012..f290a4689e5fd374e0deee4fb8ca3296c6ad6c90 100644 (file)
@@ -47,6 +47,7 @@ use OCP\AppFramework\Http;
 use OCP\AppFramework\Http\DataDisplayResponse;
 use OCP\AppFramework\Http\DataResponse;
 use OCP\AppFramework\Http\RedirectResponse;
+use OCP\EventDispatcher\IEventDispatcher;
 use OCP\Http\Client\IClientService;
 use OCP\IConfig;
 use OCP\IDateTimeFormatter;
@@ -87,6 +88,8 @@ class CheckSetupControllerTest extends TestCase {
        private $logger;
        /** @var Checker|\PHPUnit\Framework\MockObject\MockObject */
        private $checker;
+       /** @var IEventDispatcher|\PHPUnit\Framework\MockObject\MockObject */
+       private $eventDispatcher;
        /** @var EventDispatcherInterface|\PHPUnit\Framework\MockObject\MockObject */
        private $dispatcher;
        /** @var Connection|\PHPUnit\Framework\MockObject\MockObject */
@@ -137,6 +140,7 @@ class CheckSetupControllerTest extends TestCase {
                        ->willReturnCallback(function ($message, array $replace) {
                                return vsprintf($message, $replace);
                        });
+               $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
                $this->dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)
                        ->disableOriginalConstructor()->getMock();
                $this->checker = $this->getMockBuilder('\OC\IntegrityCheck\Checker')
@@ -167,6 +171,7 @@ class CheckSetupControllerTest extends TestCase {
                                $this->l10n,
                                $this->checker,
                                $this->logger,
+                               $this->eventDispatcher,
                                $this->dispatcher,
                                $this->db,
                                $this->lockingProvider,
@@ -670,6 +675,7 @@ class CheckSetupControllerTest extends TestCase {
                                $this->l10n,
                                $this->checker,
                                $this->logger,
+                               $this->eventDispatcher,
                                $this->dispatcher,
                                $this->db,
                                $this->lockingProvider,
@@ -1434,6 +1440,7 @@ Array
                        $this->l10n,
                        $this->checker,
                        $this->logger,
+                       $this->eventDispatcher,
                        $this->dispatcher,
                        $this->db,
                        $this->lockingProvider,
@@ -1488,6 +1495,7 @@ Array
                        $this->l10n,
                        $this->checker,
                        $this->logger,
+                       $this->eventDispatcher,
                        $this->dispatcher,
                        $this->db,
                        $this->lockingProvider,
index 452bcbad5dc05c3a6e6f26460cb3c718e643fd78..3a680921777917aff1e09cf61fb8d736254fd718 100644 (file)
@@ -36,6 +36,8 @@ namespace OC\Core\Command\Db;
 use Doctrine\DBAL\Platforms\PostgreSQL94Platform;
 use OC\DB\Connection;
 use OC\DB\SchemaWrapper;
+use OCP\DB\Events\AddMissingIndicesEvent;
+use OCP\EventDispatcher\IEventDispatcher;
 use OCP\IDBConnection;
 use Symfony\Component\Console\Command\Command;
 use Symfony\Component\Console\Input\InputOption;
@@ -54,12 +56,14 @@ use Symfony\Component\EventDispatcher\GenericEvent;
  */
 class AddMissingIndices extends Command {
        private Connection $connection;
+       private IEventDispatcher $eventDispatcher;
        private EventDispatcherInterface $dispatcher;
 
-       public function __construct(Connection $connection, EventDispatcherInterface $dispatcher) {
+       public function __construct(Connection $connection, IEventDispatcher $eventDispatcher, EventDispatcherInterface $dispatcher) {
                parent::__construct();
 
                $this->connection = $connection;
+               $this->eventDispatcher = $eventDispatcher;
                $this->dispatcher = $dispatcher;
        }
 
@@ -71,11 +75,37 @@ class AddMissingIndices extends Command {
        }
 
        protected function execute(InputInterface $input, OutputInterface $output): int {
-               $this->addCoreIndexes($output, $input->getOption('dry-run'));
+               $dryRun = $input->getOption('dry-run');
+
+               $this->addCoreIndexes($output, $dryRun);
 
                // Dispatch event so apps can also update indexes if needed
                $event = new GenericEvent($output);
                $this->dispatcher->dispatch(IDBConnection::ADD_MISSING_INDEXES_EVENT, $event);
+
+               $event = new AddMissingIndicesEvent();
+               $this->eventDispatcher->dispatchTyped($event);
+
+               $missingIndices = $event->getMissingIndices();
+               if ($missingIndices !== []) {
+                       $schema = new SchemaWrapper($this->connection);
+
+                       foreach ($missingIndices as $missingIndex) {
+                               if ($schema->hasTable($missingIndex['tableName'])) {
+                                       $table = $schema->getTable($missingIndex['tableName']);
+                                       if (!$table->hasIndex($missingIndex['indexName'])) {
+                                               $output->writeln('<info>Adding additional ' . $missingIndex['indexName'] . ' index to the ' . $table->getName() . ' table, this can take some time...</info>');
+                                               $table->addIndex($missingIndex['columns'], $missingIndex['indexName']);
+                                               $sqlQueries = $this->connection->migrateToSchema($schema->getWrappedSchema(), $dryRun);
+                                               if ($dryRun && $sqlQueries !== null) {
+                                                       $output->writeln($sqlQueries);
+                                               }
+                                               $output->writeln('<info>' . $table->getName() . ' table updated successfully.</info>');
+                                       }
+                               }
+                       }
+               }
+
                return 0;
        }
 
index cea794a76321e04eda9ec69a129826d0ccf6a3b6..4c8c20245dbdc9cac2d3ec5f1f32392c7f4f5701 100644 (file)
@@ -109,7 +109,7 @@ if (\OC::$server->getConfig()->getSystemValue('installed', false)) {
        $application->add(new OC\Core\Command\Db\ConvertType(\OC::$server->getConfig(), new \OC\DB\ConnectionFactory(\OC::$server->getSystemConfig())));
        $application->add(new OC\Core\Command\Db\ConvertMysqlToMB4(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection(), \OC::$server->getURLGenerator(), \OC::$server->get(LoggerInterface::class)));
        $application->add(new OC\Core\Command\Db\ConvertFilecacheBigInt(\OC::$server->get(\OC\DB\Connection::class)));
-       $application->add(new OC\Core\Command\Db\AddMissingIndices(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getEventDispatcher()));
+       $application->add(\OCP\Server::get(\OC\Core\Command\Db\AddMissingIndices::class));
        $application->add(new OC\Core\Command\Db\AddMissingColumns(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getEventDispatcher()));
        $application->add(new OC\Core\Command\Db\AddMissingPrimaryKeys(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getEventDispatcher()));
 
index 0ae7613b8fd0cc4e7bcfec03638e56b0fd33275f..10d8472344233972f8466ef95ab1e00ff63cece4 100644 (file)
@@ -186,6 +186,7 @@ return array(
     'OCP\\Contacts\\ContactsMenu\\IProvider' => $baseDir . '/lib/public/Contacts/ContactsMenu/IProvider.php',
     'OCP\\Contacts\\Events\\ContactInteractedWithEvent' => $baseDir . '/lib/public/Contacts/Events/ContactInteractedWithEvent.php',
     'OCP\\Contacts\\IManager' => $baseDir . '/lib/public/Contacts/IManager.php',
+    'OCP\\DB\\Events\\AddMissingIndicesEvent' => $baseDir . '/lib/public/DB/Events/AddMissingIndicesEvent.php',
     'OCP\\DB\\Exception' => $baseDir . '/lib/public/DB/Exception.php',
     'OCP\\DB\\IPreparedStatement' => $baseDir . '/lib/public/DB/IPreparedStatement.php',
     'OCP\\DB\\IResult' => $baseDir . '/lib/public/DB/IResult.php',
index 1efe2ab556fc2a6a32018e50362de59e2aeb2380..0550670046a0aedb72c2dd973bc77370974433bb 100644 (file)
@@ -219,6 +219,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
         'OCP\\Contacts\\ContactsMenu\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IProvider.php',
         'OCP\\Contacts\\Events\\ContactInteractedWithEvent' => __DIR__ . '/../../..' . '/lib/public/Contacts/Events/ContactInteractedWithEvent.php',
         'OCP\\Contacts\\IManager' => __DIR__ . '/../../..' . '/lib/public/Contacts/IManager.php',
+        'OCP\\DB\\Events\\AddMissingIndicesEvent' => __DIR__ . '/../../..' . '/lib/public/DB/Events/AddMissingIndicesEvent.php',
         'OCP\\DB\\Exception' => __DIR__ . '/../../..' . '/lib/public/DB/Exception.php',
         'OCP\\DB\\IPreparedStatement' => __DIR__ . '/../../..' . '/lib/public/DB/IPreparedStatement.php',
         'OCP\\DB\\IResult' => __DIR__ . '/../../..' . '/lib/public/DB/IResult.php',
diff --git a/lib/public/DB/Events/AddMissingIndicesEvent.php b/lib/public/DB/Events/AddMissingIndicesEvent.php
new file mode 100644 (file)
index 0000000..139b776
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023 Julius Härtl <jus@bitgrid.net
+ *
+ * @author Julius Härtl <jus@bitgrid.net
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCP\DB\Events;
+
+/**
+ * Event to allow apps to register information about missing database indices
+ *
+ * This event will be dispatched for checking on the admin settings and when running
+ * occ db:add-missing-indices which will then create those indices
+ *
+ * @since 28.0.0
+ */
+class AddMissingIndicesEvent extends \OCP\EventDispatcher\Event {
+       /** @var array<array-key, array{tableName: string, indexName: string, columns: string[]}> */
+       private array $missingIndices = [];
+
+       /**
+        * @param string[] $columns
+        * @since 28.0.0
+        */
+       public function addMissingIndex(string $tableName, string $indexName, array $columns): void {
+               $this->missingIndices[] = [
+                       'tableName' => $tableName,
+                       'indexName' => $indexName,
+                       'columns' => $columns
+               ];
+       }
+
+       /**
+        * @since 28.0.0
+        * @return array<array-key, array{tableName: string, indexName: string, columns: string[]}>
+        */
+       public function getMissingIndices(): array {
+               return $this->missingIndices;
+       }
+}
index 69ede2c8438650780f359bcfd2e0cdc30ee4eb24..bfc63b2aab09452a4c09905988c201f5f1dbd58d 100644 (file)
@@ -34,6 +34,7 @@
 namespace OCP;
 
 use Doctrine\DBAL\Schema\Schema;
+use OCP\DB\Events\AddMissingIndicesEvent;
 use OCP\DB\Exception;
 use OCP\DB\IPreparedStatement;
 use OCP\DB\IResult;
@@ -46,12 +47,12 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
  */
 interface IDBConnection {
        /**
-        * @deprecated 22.0.0 this is an internal event
+        * @deprecated 22.0.0 this is an internal event, use {@see AddMissingIndicesEvent} instead
         */
        public const ADD_MISSING_INDEXES_EVENT = self::class . '::ADD_MISSING_INDEXES';
 
        /**
-        * @deprecated 22.0.0 this is an internal event
+        * @deprecated 22.0.0 this is an internal event, use {@see AddMissingIndicesEvent} instead
         */
        public const CHECK_MISSING_INDEXES_EVENT = self::class . '::CHECK_MISSING_INDEXES';