2017-12-14 16:37:11 +01:00
< ? php
2019-12-03 19:57:53 +01:00
2018-05-24 10:37:33 +02:00
declare ( strict_types = 1 );
2019-12-03 19:57:53 +01:00
2017-12-14 16:37:11 +01:00
/**
* @ copyright Copyright ( c ) 2017 Bjoern Schiessle < bjoern @ schiessle . org >
*
2019-12-03 19:57:53 +01:00
* @ author Bjoern Schiessle < bjoern @ schiessle . org >
2021-06-04 21:52:51 +02:00
* @ author Christoph Wurst < christoph @ winzerhof - wurst . at >
2019-12-03 19:57:53 +01:00
* @ author Joas Schilling < coding @ schilljs . com >
2020-12-16 14:54:15 +01:00
* @ author Julius Härtl < jus @ bitgrid . net >
2020-08-24 14:54:25 +02:00
* @ author Mario Danic < mario @ lovelyhq . com >
2019-12-03 19:57:53 +01:00
* @ author Morris Jobke < hey @ morrisjobke . de >
* @ author Robin Appelman < robin @ icewind . nl >
* @ author Roeland Jago Douma < roeland @ famdouma . nl >
2020-03-31 10:49:10 +02:00
* @ author Thomas Citharel < nextcloud @ tcit . fr >
2019-12-03 19:57:53 +01:00
*
2017-12-14 16:37:11 +01:00
* @ 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
2021-06-04 21:52:51 +02:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
2017-12-14 16:37:11 +01:00
* GNU Affero General Public License for more details .
*
* You should have received a copy of the GNU Affero General Public License
2019-12-03 19:57:53 +01:00
* along with this program . If not , see < http :// www . gnu . org / licenses />.
2017-12-14 16:37:11 +01:00
*
*/
namespace OC\Core\Command\Db ;
2021-01-03 15:28:31 +01:00
use OC\DB\Connection ;
2017-12-14 16:37:11 +01:00
use OC\DB\SchemaWrapper ;
2023-07-14 10:34:09 +02:00
use OCP\DB\Events\AddMissingIndicesEvent ;
use OCP\EventDispatcher\IEventDispatcher ;
2017-12-14 16:37:11 +01:00
use Symfony\Component\Console\Command\Command ;
use Symfony\Component\Console\Input\InputInterface ;
2023-11-23 10:22:34 +01:00
use Symfony\Component\Console\Input\InputOption ;
2017-12-14 16:37:11 +01:00
use Symfony\Component\Console\Output\OutputInterface ;
2017-12-15 10:45:00 +01:00
/**
* Class AddMissingIndices
*
* if you added any new indices to the database , this is the right place to add
2020-03-11 12:29:52 +01:00
* your update routine for existing instances
2017-12-15 10:45:00 +01:00
*
* @ package OC\Core\Command\Db
*/
class AddMissingIndices extends Command {
2023-06-12 16:37:03 +02:00
public function __construct (
private Connection $connection ,
2023-07-20 00:05:59 +02:00
private IEventDispatcher $dispatcher ,
2023-06-12 16:37:03 +02:00
) {
2017-12-14 16:37:11 +01:00
parent :: __construct ();
}
protected function configure () {
$this
2017-12-15 10:45:00 +01:00
-> setName ( 'db:add-missing-indices' )
2022-02-21 18:32:17 +01:00
-> setDescription ( 'Add missing indices to the database tables' )
-> addOption ( 'dry-run' , null , InputOption :: VALUE_NONE , " Output the SQL queries instead of running them. " );
2017-12-14 16:37:11 +01:00
}
2020-06-26 14:54:51 +02:00
protected function execute ( InputInterface $input , OutputInterface $output ) : int {
2023-07-14 10:34:09 +02:00
$dryRun = $input -> getOption ( 'dry-run' );
2018-05-24 10:37:33 +02:00
// Dispatch event so apps can also update indexes if needed
2023-07-14 10:34:09 +02:00
$event = new AddMissingIndicesEvent ();
2023-07-20 00:05:59 +02:00
$this -> dispatcher -> dispatchTyped ( $event );
2023-07-14 10:34:09 +02:00
$missingIndices = $event -> getMissingIndices ();
2024-01-30 15:07:17 +01:00
$toReplaceIndices = $event -> getIndicesToReplace ();
if ( $missingIndices !== [] || $toReplaceIndices !== []) {
2023-07-14 10:34:09 +02:00
$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>' );
2023-07-19 23:19:35 +02:00
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' ]);
}
2024-01-30 15:07:17 +01:00
if ( ! $dryRun ) {
$this -> connection -> migrateToSchema ( $schema -> getWrappedSchema ());
2023-07-14 10:34:09 +02:00
}
$output -> writeln ( '<info>' . $table -> getName () . ' table updated successfully.</info>' );
}
}
}
2024-01-30 15:07:17 +01:00
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 ( '<info>Adding additional ' . $toReplaceIndex [ 'newIndexName' ] . ' index to the ' . $table -> getName () . ' table, this can take some time...</info>' );
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 ( '<info>Removing ' . $oldIndexName . ' index from the ' . $table -> getName () . ' table</info>' );
$table -> dropIndex ( $oldIndexName );
}
if ( ! $dryRun ) {
$this -> connection -> migrateToSchema ( $schema -> getWrappedSchema ());
}
$output -> writeln ( '<info>' . $table -> getName () . ' table updated successfully.</info>' );
}
}
if ( $dryRun ) {
$sqlQueries = $this -> connection -> migrateToSchema ( $schema -> getWrappedSchema (), $dryRun );
if ( $sqlQueries !== null ) {
$output -> writeln ( $sqlQueries );
}
}
2023-07-14 10:34:09 +02:00
}
2020-06-26 14:54:51 +02:00
return 0 ;
2017-12-15 10:45:00 +01:00
}
2017-12-14 16:37:11 +01:00
}