* * @author Bjoern Schiessle * @author Christoph Wurst * @author Joas Schilling * @author Julius Härtl * @author Mario Danic * @author Morris Jobke * @author Robin Appelman * @author Roeland Jago Douma * @author Thomas Citharel * * @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 . * */ namespace OC\Core\Command\Db; use OC\DB\Connection; use OC\DB\SchemaWrapper; use OCP\DB\Events\AddMissingIndicesEvent; use OCP\EventDispatcher\IEventDispatcher; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** * Class AddMissingIndices * * if you added any new indices to the database, this is the right place to add * your update routine for existing instances * * @package OC\Core\Command\Db */ class AddMissingIndices extends Command { public function __construct( private Connection $connection, private IEventDispatcher $dispatcher, ) { parent::__construct(); } protected function configure() { $this ->setName('db:add-missing-indices') ->setDescription('Add missing indices to the database tables') ->addOption('dry-run', null, InputOption::VALUE_NONE, "Output the SQL queries instead of running them."); } protected function execute(InputInterface $input, OutputInterface $output): int { $dryRun = $input->getOption('dry-run'); // Dispatch event so apps can also update indexes if needed $event = new AddMissingIndicesEvent(); $this->dispatcher->dispatchTyped($event); $missingIndices = $event->getMissingIndices(); $toReplaceIndices = $event->getIndicesToReplace(); if ($missingIndices !== [] || $toReplaceIndices !== []) { $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('Adding additional ' . $missingIndex['indexName'] . ' index to the ' . $table->getName() . ' table, this can take some time...'); if ($missingIndex['dropUnnamedIndex']) { foreach ($table->getIndexes() as $index) { $columns = $index->getColumns(); if ($columns === $missingIndex['columns']) { $table->dropIndex($index->getName()); } } } if ($missingIndex['uniqueIndex']) { $table->addUniqueIndex($missingIndex['columns'], $missingIndex['indexName'], $missingIndex['options']); } else { $table->addIndex($missingIndex['columns'], $missingIndex['indexName'], [], $missingIndex['options']); } if (!$dryRun) { $this->connection->migrateToSchema($schema->getWrappedSchema()); } $output->writeln('' . $table->getName() . ' table updated successfully.'); } } } foreach ($toReplaceIndices as $toReplaceIndex) { if ($schema->hasTable($toReplaceIndex['tableName'])) { $table = $schema->getTable($toReplaceIndex['tableName']); $allOldIndicesExists = true; foreach ($toReplaceIndex['oldIndexNames'] as $oldIndexName) { if (!$table->hasIndex($oldIndexName)) { $allOldIndicesExists = false; } } if (!$allOldIndicesExists) { continue; } $output->writeln('Adding additional ' . $toReplaceIndex['newIndexName'] . ' index to the ' . $table->getName() . ' table, this can take some time...'); if ($toReplaceIndex['uniqueIndex']) { $table->addUniqueIndex($toReplaceIndex['columns'], $toReplaceIndex['newIndexName'], $toReplaceIndex['options']); } else { $table->addIndex($toReplaceIndex['columns'], $toReplaceIndex['newIndexName'], [], $toReplaceIndex['options']); } if (!$dryRun) { $this->connection->migrateToSchema($schema->getWrappedSchema()); } foreach ($toReplaceIndex['oldIndexNames'] as $oldIndexName) { $output->writeln('Removing ' . $oldIndexName . ' index from the ' . $table->getName() . ' table'); $table->dropIndex($oldIndexName); } if (!$dryRun) { $this->connection->migrateToSchema($schema->getWrappedSchema()); } $output->writeln('' . $table->getName() . ' table updated successfully.'); } } if ($dryRun) { $sqlQueries = $this->connection->migrateToSchema($schema->getWrappedSchema(), $dryRun); if ($sqlQueries !== null) { $output->writeln($sqlQueries); } } } return 0; } }