AddMissingIndices.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OC\Core\Command\Db;
  8. use OC\DB\Connection;
  9. use OC\DB\SchemaWrapper;
  10. use OCP\DB\Events\AddMissingIndicesEvent;
  11. use OCP\EventDispatcher\IEventDispatcher;
  12. use Symfony\Component\Console\Command\Command;
  13. use Symfony\Component\Console\Input\InputInterface;
  14. use Symfony\Component\Console\Input\InputOption;
  15. use Symfony\Component\Console\Output\OutputInterface;
  16. /**
  17. * Class AddMissingIndices
  18. *
  19. * if you added any new indices to the database, this is the right place to add
  20. * your update routine for existing instances
  21. *
  22. * @package OC\Core\Command\Db
  23. */
  24. class AddMissingIndices extends Command {
  25. public function __construct(
  26. private Connection $connection,
  27. private IEventDispatcher $dispatcher,
  28. ) {
  29. parent::__construct();
  30. }
  31. protected function configure() {
  32. $this
  33. ->setName('db:add-missing-indices')
  34. ->setDescription('Add missing indices to the database tables')
  35. ->addOption('dry-run', null, InputOption::VALUE_NONE, "Output the SQL queries instead of running them.");
  36. }
  37. protected function execute(InputInterface $input, OutputInterface $output): int {
  38. $dryRun = $input->getOption('dry-run');
  39. // Dispatch event so apps can also update indexes if needed
  40. $event = new AddMissingIndicesEvent();
  41. $this->dispatcher->dispatchTyped($event);
  42. $missingIndices = $event->getMissingIndices();
  43. $toReplaceIndices = $event->getIndicesToReplace();
  44. if ($missingIndices !== [] || $toReplaceIndices !== []) {
  45. $schema = new SchemaWrapper($this->connection);
  46. foreach ($missingIndices as $missingIndex) {
  47. if ($schema->hasTable($missingIndex['tableName'])) {
  48. $table = $schema->getTable($missingIndex['tableName']);
  49. if (!$table->hasIndex($missingIndex['indexName'])) {
  50. $output->writeln('<info>Adding additional ' . $missingIndex['indexName'] . ' index to the ' . $table->getName() . ' table, this can take some time...</info>');
  51. if ($missingIndex['dropUnnamedIndex']) {
  52. foreach ($table->getIndexes() as $index) {
  53. $columns = $index->getColumns();
  54. if ($columns === $missingIndex['columns']) {
  55. $table->dropIndex($index->getName());
  56. }
  57. }
  58. }
  59. if ($missingIndex['uniqueIndex']) {
  60. $table->addUniqueIndex($missingIndex['columns'], $missingIndex['indexName'], $missingIndex['options']);
  61. } else {
  62. $table->addIndex($missingIndex['columns'], $missingIndex['indexName'], [], $missingIndex['options']);
  63. }
  64. if (!$dryRun) {
  65. $this->connection->migrateToSchema($schema->getWrappedSchema());
  66. }
  67. $output->writeln('<info>' . $table->getName() . ' table updated successfully.</info>');
  68. }
  69. }
  70. }
  71. foreach ($toReplaceIndices as $toReplaceIndex) {
  72. if ($schema->hasTable($toReplaceIndex['tableName'])) {
  73. $table = $schema->getTable($toReplaceIndex['tableName']);
  74. $allOldIndicesExists = true;
  75. foreach ($toReplaceIndex['oldIndexNames'] as $oldIndexName) {
  76. if (!$table->hasIndex($oldIndexName)) {
  77. $allOldIndicesExists = false;
  78. }
  79. }
  80. if (!$allOldIndicesExists) {
  81. continue;
  82. }
  83. $output->writeln('<info>Adding additional ' . $toReplaceIndex['newIndexName'] . ' index to the ' . $table->getName() . ' table, this can take some time...</info>');
  84. if ($toReplaceIndex['uniqueIndex']) {
  85. $table->addUniqueIndex($toReplaceIndex['columns'], $toReplaceIndex['newIndexName'], $toReplaceIndex['options']);
  86. } else {
  87. $table->addIndex($toReplaceIndex['columns'], $toReplaceIndex['newIndexName'], [], $toReplaceIndex['options']);
  88. }
  89. if (!$dryRun) {
  90. $this->connection->migrateToSchema($schema->getWrappedSchema());
  91. }
  92. foreach ($toReplaceIndex['oldIndexNames'] as $oldIndexName) {
  93. $output->writeln('<info>Removing ' . $oldIndexName . ' index from the ' . $table->getName() . ' table</info>');
  94. $table->dropIndex($oldIndexName);
  95. }
  96. if (!$dryRun) {
  97. $this->connection->migrateToSchema($schema->getWrappedSchema());
  98. }
  99. $output->writeln('<info>' . $table->getName() . ' table updated successfully.</info>');
  100. }
  101. }
  102. if ($dryRun) {
  103. $sqlQueries = $this->connection->migrateToSchema($schema->getWrappedSchema(), $dryRun);
  104. if ($sqlQueries !== null) {
  105. $output->writeln($sqlQueries);
  106. }
  107. }
  108. }
  109. return 0;
  110. }
  111. }