From 10d7cbb71f89b1e5e39a894bda1b0701760224a0 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Jul 2017 13:15:32 +0200 Subject: [PATCH] Use order by to avoid problems when chunking finds a same item again... Signed-off-by: Joas Schilling --- core/Command/Db/ConvertType.php | 39 ++++++++++++++++++++++++-------- lib/private/DB/SchemaWrapper.php | 2 +- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/core/Command/Db/ConvertType.php b/core/Command/Db/ConvertType.php index 9b8284c930..f05014936f 100644 --- a/core/Command/Db/ConvertType.php +++ b/core/Command/Db/ConvertType.php @@ -28,6 +28,8 @@ namespace OC\Core\Command\Db; +use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Schema\Table; use OC\DB\MigrationService; use OCP\DB\QueryBuilder\IQueryBuilder; use \OCP\IConfig; @@ -271,24 +273,23 @@ class ConvertType extends Command implements CompletionAwareInterface { /** * @param Connection $fromDB * @param Connection $toDB - * @param $table + * @param Table $table * @param InputInterface $input * @param OutputInterface $output * @suppress SqlInjectionChecker */ - protected function copyTable(Connection $fromDB, Connection $toDB, $table, InputInterface $input, OutputInterface $output) { - if ($table === $toDB->getPrefix() . 'migrations') { + protected function copyTable(Connection $fromDB, Connection $toDB, Table $table, InputInterface $input, OutputInterface $output) { + if ($table->getName() === $toDB->getPrefix() . 'migrations') { $output->writeln('Skipping migrations table because it was already filled by running the migrations'); return; } - $chunkSize = $input->getOption('chunk-size'); $query = $fromDB->getQueryBuilder(); $query->automaticTablePrefix(false); $query->selectAlias($query->createFunction('COUNT(*)'), 'num_entries') - ->from($table); + ->from($table->getName()); $result = $query->execute(); $count = $result->fetchColumn(); $result->closeCursor(); @@ -306,12 +307,30 @@ class ConvertType extends Command implements CompletionAwareInterface { $query = $fromDB->getQueryBuilder(); $query->automaticTablePrefix(false); $query->select('*') - ->from($table) + ->from($table->getName()) ->setMaxResults($chunkSize); + try { + $orderColumns = $table->getPrimaryKeyColumns(); + } catch (DBALException $e) { + $orderColumns = []; + } + foreach ($table->getIndexes() as $index) { + if ($index->isUnique()) { + $orderColumns = array_merge($orderColumns, $index->getUnquotedColumns()); + } + } + $orderColumns = array_unique($orderColumns); + + if (!empty($orderColumns)) { + foreach ($orderColumns as $column) { + $query->addOrderBy($column); + } + } + $insertQuery = $toDB->getQueryBuilder(); $insertQuery->automaticTablePrefix(false); - $insertQuery->insert($table); + $insertQuery->insert($table->getName()); $parametersCreated = false; for ($chunk = 0; $chunk < $numChunks; $chunk++) { @@ -329,7 +348,7 @@ class ConvertType extends Command implements CompletionAwareInterface { } foreach ($row as $key => $value) { - $type = $this->getColumnType($table, $key); + $type = $this->getColumnType($table->getName(), $key); if ($type !== false) { $insertQuery->setParameter($key, $value, $type); } else { @@ -365,11 +384,13 @@ class ConvertType extends Command implements CompletionAwareInterface { protected function convertDB(Connection $fromDB, Connection $toDB, array $tables, InputInterface $input, OutputInterface $output) { $this->config->setSystemValue('maintenance', true); + $schema = $fromDB->createSchema(); + try { // copy table rows foreach($tables as $table) { $output->writeln($table); - $this->copyTable($fromDB, $toDB, $table, $input, $output); + $this->copyTable($fromDB, $toDB, $schema->getTable($table), $input, $output); } if ($input->getArgument('type') === 'pgsql') { $tools = new \OC\DB\PgSqlTools($this->config); diff --git a/lib/private/DB/SchemaWrapper.php b/lib/private/DB/SchemaWrapper.php index 0be45d8d3f..d686d7e63e 100644 --- a/lib/private/DB/SchemaWrapper.php +++ b/lib/private/DB/SchemaWrapper.php @@ -34,7 +34,7 @@ class SchemaWrapper { protected $schema; /** @var array */ - protected $tablesToDelete; + protected $tablesToDelete = []; /** * @param IDBConnection $connection