From f6c48b1548763e0eda66af7c2720d363e1671090 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 18 Jul 2017 13:37:01 +0200 Subject: [PATCH 01/16] Add a script to generate a migration from database.xml Signed-off-by: Joas Schilling --- .../Command/Db/Migrations/GenerateCommand.php | 18 +- .../GenerateFromSchemaFileCommand.php | 201 ++++++++++++++++++ core/register_command.php | 1 + 3 files changed, 215 insertions(+), 5 deletions(-) create mode 100644 core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php diff --git a/core/Command/Db/Migrations/GenerateCommand.php b/core/Command/Db/Migrations/GenerateCommand.php index e6c38d06e5..f8a992940f 100644 --- a/core/Command/Db/Migrations/GenerateCommand.php +++ b/core/Command/Db/Migrations/GenerateCommand.php @@ -36,7 +36,7 @@ use Symfony\Component\Console\Output\OutputInterface; class GenerateCommand extends Command { - private static $_templateSimple = + protected static $_templateSimple = '; @@ -66,7 +66,7 @@ class extends SimpleMigrationStep { * @since 13.0.0 */ public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { - return null; + } /** @@ -81,7 +81,7 @@ class extends SimpleMigrationStep { '; /** @var IDBConnection */ - private $connection; + protected $connection; /** * @param IDBConnection $connection @@ -123,16 +123,24 @@ class extends SimpleMigrationStep { /** * @param MigrationService $ms * @param string $className + * @param string $schemaBody * @return string */ - private function generateMigration(MigrationService $ms, $className) { + protected function generateMigration(MigrationService $ms, $className, $schemaBody = '') { + if ($schemaBody === '') { + $schemaBody = "\t\t" . 'return null;'; + } + + $placeHolders = [ '', '', + '', ]; $replacements = [ $ms->getMigrationsNamespace(), $className, + $schemaBody, ]; $code = str_replace($placeHolders, $replacements, self::$_templateSimple); $dir = $ms->getMigrationsDirectory(); @@ -147,7 +155,7 @@ class extends SimpleMigrationStep { return $path; } - private function ensureMigrationDirExists($directory) { + protected function ensureMigrationDirExists($directory) { if (file_exists($directory) && is_dir($directory)) { return; } diff --git a/core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php b/core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php new file mode 100644 index 0000000000..38f8d82b96 --- /dev/null +++ b/core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php @@ -0,0 +1,201 @@ + + * + * @author Joas Schilling + * @author Julius Haertl + * + * @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\Migrations; + + +use Doctrine\DBAL\Schema\Schema; +use OC\DB\MDB2SchemaReader; +use OC\DB\MigrationService; +use OC\Migration\ConsoleOutput; +use OCP\App\IAppManager; +use OCP\IConfig; +use OCP\IDBConnection; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class GenerateFromSchemaFileCommand extends GenerateCommand { + + /** @var IConfig */ + protected $config; + + /** @var IAppManager */ + protected $appManager; + + public function __construct(IConfig $config, IAppManager $appManager, IDBConnection $connection) { + parent::__construct($connection); + $this->config = $config; + $this->appManager = $appManager; + } + + + protected function configure() { + parent::configure(); + + $this->setName('migrations:generate-from-schema'); + } + + public function execute(InputInterface $input, OutputInterface $output) { + $appName = $input->getArgument('app'); + $version = $input->getArgument('version'); + + if (!preg_match('/^\d{1,16}$/',$version)) { + $output->writeln('The given version is invalid. Only 0-9 are allowed (max. 16 digits)'); + return 1; + } + + $reader = new MDB2SchemaReader($this->config, $this->connection->getDatabasePlatform()); + $schema = new Schema(); + if ($appName === 'core') { + $reader->loadSchemaFromFile(\OC::$SERVERROOT . '/db_structure.xml', $schema); + } else { + if (!file_exists($this->appManager->getAppPath($appName) . '/appinfo/database.xml')) { + throw new \RuntimeException('App ' . $appName . ' does not have a database.xml file'); + } + $reader->loadSchemaFromFile($this->appManager->getAppPath($appName) . '/appinfo/database.xml', $schema); + } + + + $schemaBody = $this->schemaToMigration($schema); + + $ms = new MigrationService($appName, $this->connection, new ConsoleOutput($output)); + + $date = date('YmdHis'); + $path = $this->generateMigration($ms, 'Version' . $version . 'Date' . $date, $schemaBody); + + $output->writeln("New migration class has been generated to $path"); + return 0; + } + + /** + * @param Schema $schema + * @return string + */ + protected function schemaToMigration(Schema $schema) { + $content = <<<'EOT' + /** @var Schema $schema */ + $schema = $schemaClosure(); + +EOT; + + foreach ($schema->getTables() as $table) { + $content .= str_replace('{{table-name}}', substr($table->getName(), 3), <<<'EOT' + + if (!$schema->hasTable('{{table-name}}')) { + $table = $schema->createTable('{{table-name}}'); + +EOT + ); + + foreach ($table->getColumns() as $column) { + $content .= str_replace(['{{name}}', '{{type}}'], [$column->getName(), $column->getType()->getName()], <<<'EOT' + $table->addColumn('{{name}}', '{{type}}', [ + +EOT + ); + if ($column->getAutoincrement()) { + $content .= <<<'EOT' + 'autoincrement' => true, + +EOT; + } + $content .= str_replace('{{notnull}}', $column->getNotnull() ? 'true' : 'false', <<<'EOT' + 'notnull' => {{notnull}}, + +EOT + ); + if ($column->getLength() !== null) { + $content .= str_replace('{{length}}', $column->getLength(), <<<'EOT' + 'length' => {{length}}, + +EOT + ); + } + $default = $column->getDefault(); + if ($default !== null) { + $default = is_numeric($default) ? $default : "'$default'"; + $content .= str_replace('{{default}}', $default, <<<'EOT' + 'default' => {{default}}, + +EOT + ); + } + $content .= <<<'EOT' + ]); + +EOT; + } + + $content .= <<<'EOT' + +EOT; + + $primaryKey = $table->getPrimaryKey(); + if ($primaryKey !== null) { + $content .= str_replace('{{columns}}', implode('\', \'', $primaryKey->getUnquotedColumns()), <<<'EOT' + $table->setPrimaryKey(['{{columns}}']); + +EOT + ); + } + + foreach ($table->getIndexes() as $index) { + if ($index->isPrimary()) { + continue; + } + + if ($index->isUnique()) { + $content .= str_replace( + ['{{columns}}', '{{name}}'], + [implode('\', \'', $index->getUnquotedColumns()), $index->getName()], + <<<'EOT' + $table->addUniqueIndex(['{{columns}}'], '{{name}}'); + +EOT + ); + } else { + $content .= str_replace( + ['{{columns}}', '{{name}}'], + [implode('\', \'', $index->getUnquotedColumns()), $index->getName()], + <<<'EOT' + $table->addIndex(['{{columns}}'], '{{name}}'); + +EOT + ); + } + } + + $content .= <<<'EOT' + } + +EOT; + } + + $content .= <<<'EOT' + return $schema; +EOT; + + return $content; + } +} diff --git a/core/register_command.php b/core/register_command.php index bfb1138c5e..c65ff8d006 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -88,6 +88,7 @@ if (\OC::$server->getConfig()->getSystemValue('installed', false)) { $application->add(new OC\Core\Command\Db\Migrations\StatusCommand(\OC::$server->getDatabaseConnection())); $application->add(new OC\Core\Command\Db\Migrations\MigrateCommand(\OC::$server->getDatabaseConnection())); $application->add(new OC\Core\Command\Db\Migrations\GenerateCommand(\OC::$server->getDatabaseConnection())); + $application->add(new OC\Core\Command\Db\Migrations\GenerateFromSchemaFileCommand(\OC::$server->getConfig(), \OC::$server->getAppManager(), \OC::$server->getDatabaseConnection())); $application->add(new OC\Core\Command\Db\Migrations\ExecuteCommand(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig())); $application->add(new OC\Core\Command\Encryption\Disable(\OC::$server->getConfig())); From 5e04254d40b427f43ac0cf05f684812c4008aaf5 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 18 Jul 2017 14:20:29 +0200 Subject: [PATCH 02/16] Install from migrations Signed-off-by: Joas Schilling --- .../Version13000Date20170718121200.php | 897 +++++++ db_structure.xml | 2223 ----------------- lib/private/Setup.php | 3 +- lib/private/Setup/AbstractDatabase.php | 5 +- lib/private/Setup/MySQL.php | 6 +- lib/private/Setup/OCI.php | 9 +- lib/private/Setup/PostgreSQL.php | 5 - lib/private/Setup/Sqlite.php | 1 - 8 files changed, 901 insertions(+), 2248 deletions(-) create mode 100644 core/Migrations/Version13000Date20170718121200.php delete mode 100644 db_structure.xml diff --git a/core/Migrations/Version13000Date20170718121200.php b/core/Migrations/Version13000Date20170718121200.php new file mode 100644 index 0000000000..81743bd203 --- /dev/null +++ b/core/Migrations/Version13000Date20170718121200.php @@ -0,0 +1,897 @@ +hasTable('appconfig')) { + $table = $schema->createTable('appconfig'); + $table->addColumn('appid', 'string', [ + 'notnull' => true, + 'length' => 32, + 'default' => '', + ]); + $table->addColumn('configkey', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('configvalue', 'text', [ + 'notnull' => false, + ]); + $table->setPrimaryKey(['appid', 'configkey']); + $table->addIndex(['configkey'], 'appconfig_config_key_index'); + $table->addIndex(['appid'], 'appconfig_appid_key'); + } + + if (!$schema->hasTable('storages')) { + $table = $schema->createTable('storages'); + $table->addColumn('id', 'string', [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('numeric_id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('available', 'integer', [ + 'notnull' => true, + 'default' => 1, + ]); + $table->addColumn('last_checked', 'integer', [ + 'notnull' => false, + ]); + $table->setPrimaryKey(['numeric_id']); + $table->addUniqueIndex(['id'], 'storages_id_index'); + } + + if (!$schema->hasTable('mounts')) { + $table = $schema->createTable('mounts'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('storage_id', 'integer', [ + 'notnull' => true, + ]); + $table->addColumn('root_id', 'integer', [ + 'notnull' => true, + ]); + $table->addColumn('user_id', 'string', [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('mount_point', 'string', [ + 'notnull' => true, + 'length' => 4000, + ]); + $table->addColumn('mount_id', 'integer', [ + 'notnull' => false, + ]); + $table->setPrimaryKey(['id']); + $table->addIndex(['user_id'], 'mounts_user_index'); + $table->addIndex(['storage_id'], 'mounts_storage_index'); + $table->addIndex(['root_id'], 'mounts_root_index'); + $table->addIndex(['mount_id'], 'mounts_mount_id_index'); + $table->addUniqueIndex(['user_id', 'root_id'], 'mounts_user_root_index'); + } + + if (!$schema->hasTable('mimetypes')) { + $table = $schema->createTable('mimetypes'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('mimetype', 'string', [ + 'notnull' => true, + 'length' => 255, + 'default' => '', + ]); + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['mimetype'], 'mimetype_id_index'); + } + + if (!$schema->hasTable('filecache')) { + $table = $schema->createTable('filecache'); + $table->addColumn('fileid', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('storage', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('path', 'string', [ + 'notnull' => false, + 'length' => 4000, + ]); + $table->addColumn('path_hash', 'string', [ + 'notnull' => true, + 'length' => 32, + 'default' => '', + ]); + $table->addColumn('parent', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('name', 'string', [ + 'notnull' => false, + 'length' => 250, + ]); + $table->addColumn('mimetype', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('mimepart', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('size', 'bigint', [ + 'notnull' => true, + 'length' => 8, + 'default' => 0, + ]); + $table->addColumn('mtime', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('storage_mtime', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('encrypted', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('unencrypted_size', 'bigint', [ + 'notnull' => true, + 'length' => 8, + 'default' => 0, + ]); + $table->addColumn('etag', 'string', [ + 'notnull' => false, + 'length' => 40, + ]); + $table->addColumn('permissions', 'integer', [ + 'notnull' => false, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('checksum', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->setPrimaryKey(['fileid']); + $table->addUniqueIndex(['storage', 'path_hash'], 'fs_storage_path_hash'); + $table->addIndex(['parent', 'name'], 'fs_parent_name_hash'); + $table->addIndex(['storage', 'mimetype'], 'fs_storage_mimetype'); + $table->addIndex(['storage', 'mimepart'], 'fs_storage_mimepart'); + $table->addIndex(['storage', 'size', 'fileid'], 'fs_storage_size'); + } + + if (!$schema->hasTable('group_user')) { + $table = $schema->createTable('group_user'); + $table->addColumn('gid', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('uid', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->setPrimaryKey(['gid', 'uid']); + $table->addIndex(['uid'], 'gu_uid_index'); + } + + if (!$schema->hasTable('group_admin')) { + $table = $schema->createTable('group_admin'); + $table->addColumn('gid', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('uid', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->setPrimaryKey(['gid', 'uid']); + $table->addIndex(['uid'], 'group_admin_uid'); + } + + if (!$schema->hasTable('groups')) { + $table = $schema->createTable('groups'); + $table->addColumn('gid', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->setPrimaryKey(['gid']); + } + + if (!$schema->hasTable('preferences')) { + $table = $schema->createTable('preferences'); + $table->addColumn('userid', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('appid', 'string', [ + 'notnull' => true, + 'length' => 32, + 'default' => '', + ]); + $table->addColumn('configkey', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('configvalue', 'text', [ + 'notnull' => false, + ]); + $table->setPrimaryKey(['userid', 'appid', 'configkey']); + } + + if (!$schema->hasTable('properties')) { + $table = $schema->createTable('properties'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('userid', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('propertypath', 'string', [ + 'notnull' => true, + 'length' => 255, + 'default' => '', + ]); + $table->addColumn('propertyname', 'string', [ + 'notnull' => true, + 'length' => 255, + 'default' => '', + ]); + $table->addColumn('propertyvalue', 'text', [ + 'notnull' => true, + ]); + $table->setPrimaryKey(['id']); + $table->addIndex(['userid'], 'property_index'); + } + + if (!$schema->hasTable('share')) { + $table = $schema->createTable('share'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('share_type', 'smallint', [ + 'notnull' => true, + 'length' => 1, + 'default' => 0, + ]); + $table->addColumn('share_with', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('password', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('uid_owner', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('uid_initiator', 'string', [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('parent', 'integer', [ + 'notnull' => false, + 'length' => 4, + ]); + $table->addColumn('item_type', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('item_source', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('item_target', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + $table->addColumn('file_source', 'integer', [ + 'notnull' => false, + 'length' => 4, + ]); + $table->addColumn('file_target', 'string', [ + 'notnull' => false, + 'length' => 512, + ]); + $table->addColumn('permissions', 'smallint', [ + 'notnull' => true, + 'length' => 1, + 'default' => 0, + ]); + $table->addColumn('stime', 'bigint', [ + 'notnull' => true, + 'length' => 8, + 'default' => 0, + ]); + $table->addColumn('accepted', 'smallint', [ + 'notnull' => true, + 'length' => 1, + 'default' => 0, + ]); + $table->addColumn('expiration', 'datetime', [ + 'notnull' => false, + ]); + $table->addColumn('token', 'string', [ + 'notnull' => false, + 'length' => 32, + ]); + $table->addColumn('mail_send', 'smallint', [ + 'notnull' => true, + 'length' => 1, + 'default' => 0, + ]); + $table->addColumn('share_name', 'string', [ + 'notnull' => false, + 'length' => 64, + ]); + $table->setPrimaryKey(['id']); + $table->addIndex(['item_type', 'share_type'], 'item_share_type_index'); + $table->addIndex(['file_source'], 'file_source_index'); + $table->addIndex(['token'], 'token_index'); + } + + if (!$schema->hasTable('jobs')) { + $table = $schema->createTable('jobs'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('class', 'string', [ + 'notnull' => true, + 'length' => 255, + 'default' => '', + ]); + $table->addColumn('argument', 'string', [ + 'notnull' => true, + 'length' => 4000, + 'default' => '', + ]); + $table->addColumn('last_run', 'integer', [ + 'notnull' => false, + 'default' => 0, + ]); + $table->addColumn('last_checked', 'integer', [ + 'notnull' => false, + 'default' => 0, + ]); + $table->addColumn('reserved_at', 'integer', [ + 'notnull' => false, + 'default' => 0, + ]); + $table->addColumn('execution_duration', 'integer', [ + 'notnull' => true, + 'default' => 0, + ]); + $table->setPrimaryKey(['id']); + $table->addIndex(['class'], 'job_class_index'); + } + + if (!$schema->hasTable('users')) { + $table = $schema->createTable('users'); + $table->addColumn('uid', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('displayname', 'string', [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('password', 'string', [ + 'notnull' => true, + 'length' => 255, + 'default' => '', + ]); + $table->setPrimaryKey(['uid']); + } + + if (!$schema->hasTable('authtoken')) { + $table = $schema->createTable('authtoken'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('uid', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('login_name', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('password', 'text', [ + 'notnull' => false, + ]); + $table->addColumn('name', 'text', [ + 'notnull' => true, + 'default' => '', + ]); + $table->addColumn('token', 'string', [ + 'notnull' => true, + 'length' => 200, + 'default' => '', + ]); + $table->addColumn('type', 'smallint', [ + 'notnull' => true, + 'length' => 2, + 'default' => 0, + ]); + $table->addColumn('remember', 'smallint', [ + 'notnull' => true, + 'length' => 1, + 'default' => 0, + ]); + $table->addColumn('last_activity', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('last_check', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('scope', 'text', [ + 'notnull' => false, + ]); + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['token'], 'authtoken_token_index'); + $table->addIndex(['last_activity'], 'authtoken_last_activity_index'); + } + + if (!$schema->hasTable('bruteforce_attempts')) { + $table = $schema->createTable('bruteforce_attempts'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('action', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('occurred', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('ip', 'string', [ + 'notnull' => true, + 'length' => 255, + 'default' => '', + ]); + $table->addColumn('subnet', 'string', [ + 'notnull' => true, + 'length' => 255, + 'default' => '', + ]); + $table->addColumn('metadata', 'string', [ + 'notnull' => true, + 'length' => 255, + 'default' => '', + ]); + $table->setPrimaryKey(['id']); + $table->addIndex(['ip'], 'bruteforce_attempts_ip'); + $table->addIndex(['subnet'], 'bruteforce_attempts_subnet'); + } + + if (!$schema->hasTable('vcategory')) { + $table = $schema->createTable('vcategory'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('uid', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('type', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('category', 'string', [ + 'notnull' => true, + 'length' => 255, + 'default' => '', + ]); + $table->setPrimaryKey(['id']); + $table->addIndex(['uid'], 'uid_index'); + $table->addIndex(['type'], 'type_index'); + $table->addIndex(['category'], 'category_index'); + } + + if (!$schema->hasTable('vcategory_to_object')) { + $table = $schema->createTable('vcategory_to_object'); + $table->addColumn('objid', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('categoryid', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('type', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->setPrimaryKey(['categoryid', 'objid', 'type']); + $table->addIndex(['objid', 'type'], 'vcategory_objectd_index'); + } + + if (!$schema->hasTable('systemtag')) { + $table = $schema->createTable('systemtag'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('name', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('visibility', 'smallint', [ + 'notnull' => true, + 'length' => 1, + 'default' => 1, + ]); + $table->addColumn('editable', 'smallint', [ + 'notnull' => true, + 'length' => 1, + 'default' => 1, + ]); + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['name', 'visibility', 'editable'], 'tag_ident'); + } + + if (!$schema->hasTable('systemtag_object_mapping')) { + $table = $schema->createTable('systemtag_object_mapping'); + $table->addColumn('objectid', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('objecttype', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('systemtagid', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addUniqueIndex(['objecttype', 'objectid', 'systemtagid'], 'mapping'); + } + + if (!$schema->hasTable('systemtag_group')) { + $table = $schema->createTable('systemtag_group'); + $table->addColumn('systemtagid', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('gid', 'string', [ + 'notnull' => true, + ]); + $table->setPrimaryKey(['gid', 'systemtagid']); + } + + if (!$schema->hasTable('file_locks')) { + $table = $schema->createTable('file_locks'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('lock', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('key', 'string', [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('ttl', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => -1, + ]); + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['key'], 'lock_key_index'); + $table->addIndex(['ttl'], 'lock_ttl_index'); + } + + if (!$schema->hasTable('comments')) { + $table = $schema->createTable('comments'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('parent_id', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('topmost_parent_id', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('children_count', 'integer', [ + 'notnull' => true, + 'length' => 4, + 'default' => 0, + ]); + $table->addColumn('actor_type', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('actor_id', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('message', 'text', [ + 'notnull' => false, + ]); + $table->addColumn('verb', 'string', [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('creation_timestamp', 'datetime', [ + 'notnull' => false, + ]); + $table->addColumn('latest_child_timestamp', 'datetime', [ + 'notnull' => false, + ]); + $table->addColumn('object_type', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('object_id', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->setPrimaryKey(['id']); + $table->addIndex(['parent_id'], 'comments_parent_id_index'); + $table->addIndex(['topmost_parent_id'], 'comments_topmost_parent_id_idx'); + $table->addIndex(['object_type', 'object_id', 'creation_timestamp'], 'comments_object_index'); + $table->addIndex(['actor_type', 'actor_id'], 'comments_actor_index'); + } + + if (!$schema->hasTable('comments_read_markers')) { + $table = $schema->createTable('comments_read_markers'); + $table->addColumn('user_id', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('marker_datetime', 'datetime', [ + 'notnull' => false, + ]); + $table->addColumn('object_type', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('object_id', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addIndex(['object_type', 'object_id'], 'comments_marker_object_index'); + $table->addUniqueIndex(['user_id', 'object_type', 'object_id'], 'comments_marker_index'); + } + + if (!$schema->hasTable('credentials')) { + $table = $schema->createTable('credentials'); + $table->addColumn('user', 'string', [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('identifier', 'string', [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('credentials', 'text', [ + 'notnull' => false, + ]); + $table->setPrimaryKey(['user', 'identifier']); + $table->addIndex(['user'], 'credentials_user'); + } + + if (!$schema->hasTable('admin_sections')) { + $table = $schema->createTable('admin_sections'); + $table->addColumn('id', 'string', [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('class', 'string', [ + 'notnull' => true, + 'length' => 255, + 'default' => '', + ]); + $table->addColumn('priority', 'smallint', [ + 'notnull' => true, + 'length' => 1, + 'default' => 0, + ]); + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['class'], 'admin_sections_class'); + } + + if (!$schema->hasTable('admin_settings')) { + $table = $schema->createTable('admin_settings'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('class', 'string', [ + 'notnull' => true, + 'length' => 255, + 'default' => '', + ]); + $table->addColumn('section', 'string', [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('priority', 'smallint', [ + 'notnull' => true, + 'length' => 1, + 'default' => 0, + ]); + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['class'], 'admin_settings_class'); + $table->addIndex(['section'], 'admin_settings_section'); + } + + if (!$schema->hasTable('personal_sections')) { + $table = $schema->createTable('personal_sections'); + $table->addColumn('id', 'string', [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('class', 'string', [ + 'notnull' => true, + 'length' => 255, + 'default' => '', + ]); + $table->addColumn('priority', 'smallint', [ + 'notnull' => true, + 'length' => 1, + 'default' => 0, + ]); + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['class'], 'personal_sections_class'); + } + + if (!$schema->hasTable('personal_settings')) { + $table = $schema->createTable('personal_settings'); + $table->addColumn('id', 'integer', [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 4, + ]); + $table->addColumn('class', 'string', [ + 'notnull' => true, + 'length' => 255, + 'default' => '', + ]); + $table->addColumn('section', 'string', [ + 'notnull' => false, + 'length' => 64, + ]); + $table->addColumn('priority', 'smallint', [ + 'notnull' => true, + 'length' => 1, + 'default' => 0, + ]); + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['class'], 'personal_settings_class'); + $table->addIndex(['section'], 'personal_settings_section'); + } + + if (!$schema->hasTable('accounts')) { + $table = $schema->createTable('accounts'); + $table->addColumn('uid', 'string', [ + 'notnull' => true, + 'length' => 64, + 'default' => '', + ]); + $table->addColumn('data', 'text', [ + 'notnull' => true, + 'default' => '', + ]); + $table->setPrimaryKey(['uid']); + } + return $schema; + } + + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `Schema` + * @param array $options + * @since 13.0.0 + */ + public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) { + } +} diff --git a/db_structure.xml b/db_structure.xml deleted file mode 100644 index 65bdb69d95..0000000000 --- a/db_structure.xml +++ /dev/null @@ -1,2223 +0,0 @@ - - - - *dbname* - true - false - - utf8 - - - - - *dbprefix*appconfig - - - - - appid - text - - true - 32 - - - - configkey - text - - true - 64 - - - - configvalue - clob - false - - - - appconfig_appid_key_index - true - true - - appid - ascending - - - configkey - ascending - - - - appconfig_config_key_index - - configkey - ascending - - - - appconfig_appid_key - - appid - ascending - - - - - -
- - - - - *dbprefix*storages - - - - - id - text - - false - 64 - - - - numeric_id - integer - 0 - true - 1 - 4 - - - - available - integer - 1 - true - - - - last_checked - integer - - - - storages_id_index - true - - id - ascending - - - - - -
- - - - - *dbprefix*mounts - - - - - id - integer - 0 - true - 1 - 4 - - - - storage_id - integer - true - - - - - root_id - integer - true - - - - user_id - text - true - 64 - - - - mount_point - text - true - 4000 - - - - mount_id - integer - - - - mounts_user_index - false - - user_id - ascending - - - - - mounts_storage_index - false - - storage_id - ascending - - - - - mounts_root_index - false - - root_id - ascending - - - - - mounts_mount_id_index - false - - mount_id - ascending - - - - - mounts_user_root_index - true - - user_id - ascending - - - root_id - ascending - - - - - -
- - - - - *dbprefix*mimetypes - - - - - id - integer - 0 - true - 1 - 4 - - - - mimetype - text - - true - 255 - - - - mimetype_id_index - true - - mimetype - ascending - - - - - -
- - - - - *dbprefix*filecache - - - - - fileid - integer - 0 - true - 1 - 4 - - - - - storage - integer - - true - 4 - - - - path - text - - false - 4000 - - - - path_hash - text - - true - 32 - - - - - parent - integer - - true - 4 - - - - name - text - - false - 250 - - - - - mimetype - integer - - true - 4 - - - - - mimepart - integer - - true - 4 - - - - size - integer - - true - 8 - - - - mtime - integer - - true - 4 - - - - storage_mtime - integer - - true - 4 - - - - encrypted - integer - 0 - true - 4 - - - - unencrypted_size - integer - 0 - true - 8 - - - - etag - text - - false - 40 - - - - permissions - integer - 0 - false - 4 - - - - checksum - text - - false - 255 - - - - - fs_storage_path_hash - true - - storage - ascending - - - path_hash - ascending - - - - - fs_parent_name_hash - - parent - ascending - - - name - ascending - - - - - fs_storage_mimetype - - storage - ascending - - - mimetype - ascending - - - - - fs_storage_mimepart - - storage - ascending - - - mimepart - ascending - - - - - fs_storage_size - - storage - ascending - - - size - ascending - - - fileid - - - - - -
- - - - - *dbprefix*group_user - - - - - - gid - text - - true - 64 - - - - - uid - text - - true - 64 - - - - gu_gid_uid_index - true - true - - gid - ascending - - - uid - ascending - - - - - gu_uid_index - - uid - ascending - - - - - -
- - - - - *dbprefix*group_admin - - - - - - gid - text - - true - 64 - - - - - uid - text - - true - 64 - - - group_admin_uid - - uid - ascending - - - - - ga_gid_uid_index - true - true - - gid - ascending - - - uid - ascending - - - - - -
- - - - - *dbprefix*groups - - - - - gid - text - - true - 64 - - - - groups_pKey - true - - gid - ascending - - - - - -
- - - - - *dbprefix*preferences - - - - - - userid - text - - true - 64 - - - - appid - text - - true - 32 - - - - configkey - text - - true - 64 - - - - configvalue - clob - false - - - - pref_userid_appid_key_index - true - true - - userid - ascending - - - appid - ascending - - - configkey - ascending - - - - - -
- - - - - *dbprefix*properties - - - - - id - 1 - integer - 0 - true - 4 - - - - - userid - text - - true - 64 - - - - propertypath - text - - true - 255 - - - - propertyname - text - - true - 255 - - - - propertyvalue - clob - true - - - - property_index - - userid - ascending - - - - - -
- - - - - *dbprefix*share - - - - - id - 1 - integer - 0 - true - 4 - - - - - share_type - integer - 0 - true - 1 - - - - - share_with - text - - false - 255 - - - password - text - - false - 255 - - - - - - uid_owner - text - - true - 64 - - - - - - uid_initiator - text - - false - 64 - - - - - - - parent - integer - false - 4 - - - - - item_type - text - - true - 64 - - - - - item_source - text - - false - 255 - - - - item_target - text - - false - 255 - - - - - file_source - integer - false - 4 - - - - file_target - text - - false - 512 - - - - - permissions - integer - 0 - true - 1 - - - - - stime - integer - 0 - true - 8 - - - - - accepted - integer - 0 - true - 1 - - - - - expiration - timestamp - - false - - - - token - text - - false - 32 - - - - mail_send - integer - 0 - true - 1 - - - - share_name - text - - false - 64 - - - - item_share_type_index - - item_type - ascending - - - share_type - ascending - - - - file_source_index - - file_source - ascending - - - - token_index - - token - ascending - - - - -
- - - - - *dbprefix*jobs - - - - - id - integer - 0 - true - 1 - true - 4 - - - - class - text - - true - 255 - - - - argument - text - - true - 4000 - - - - - last_run - integer - - false - - - - - last_checked - integer - - false - - - - - reserved_at - integer - - false - - - - - execution_duration - integer - - true - - - - job_class_index - - class - ascending - - - - - -
- - - - - *dbprefix*users - - - - - uid - text - - true - 64 - - - - displayname - text - - 64 - - - - password - text - - true - 255 - - - - users_pKey - true - - uid - ascending - - - - - -
- - - *dbprefix*authtoken - - - - - id - integer - 0 - true - 1 - true - 4 - - - - - uid - text - - true - 64 - - - - login_name - text - - true - 64 - - - - password - clob - - false - - - - name - clob - - true - - - - token - text - - true - 200 - - - - type - integer - 0 - true - true - 2 - - - - remember - integer - 0 - true - true - 1 - - - - last_activity - integer - 0 - true - true - 4 - - - - last_check - integer - 0 - true - true - 4 - - - - scope - clob - - false - - - - authtoken_token_index - true - - token - ascending - - - - - authtoken_last_activity_index - - last_activity - ascending - - - - -
- - - - - *dbprefix*bruteforce_attempts - - - - id - integer - 0 - true - 1 - true - 4 - - - - action - text - - true - 64 - - - - occurred - integer - 0 - true - true - 4 - - - - ip - text - - true - 255 - - - - subnet - text - - true - 255 - - - - metadata - text - - true - 255 - - - - bruteforce_attempts_ip - - ip - ascending - - - - bruteforce_attempts_subnet - - subnet - ascending - - - - - -
- - - - - *dbprefix*vcategory - - - - - id - integer - 0 - true - 1 - true - 4 - - - - - uid - text - - true - 64 - - - - type - text - - true - 64 - - - - category - text - - true - 255 - - - - uid_index - - uid - ascending - - - - - type_index - - type - ascending - - - - - category_index - - category - ascending - - - - -
- - - - - *dbprefix*vcategory_to_object - - - - - objid - integer - 0 - true - true - 4 - - - - - categoryid - integer - 0 - true - true - 4 - - - - type - text - - true - 64 - - - - true - true - category_object_index - - categoryid - ascending - - - objid - ascending - - - type - ascending - - - - - vcategory_objectd_index - - objid - ascending - - - type - ascending - - - - - -
- - - - *dbprefix*systemtag - - - - - id - integer - 0 - true - 1 - true - 4 - - - - - name - text - - true - 64 - - - - - visibility - integer - 1 - true - 1 - - - - - editable - integer - 1 - true - 1 - - - - tag_ident - true - - name - ascending - - - visibility - ascending - - - editable - ascending - - - - -
- - - - - *dbprefix*systemtag_object_mapping - - - - - - objectid - text - - true - 64 - - - - - objecttype - text - - true - 64 - - - - - systemtagid - integer - 0 - true - true - 4 - - - - true - mapping - - objecttype - ascending - - - objectid - ascending - - - systemtagid - ascending - - - - - -
- - - - - *dbprefix*systemtag_group - - - - - - systemtagid - integer - 0 - true - true - 4 - - - - gid - string - true - - - - systemtag_group - true - true - - gid - ascending - - - systemtagid - ascending - - - - - -
- - - - - *dbprefix*file_locks - - - - - id - integer - 0 - true - true - 4 - 1 - - - - lock - integer - 0 - true - 4 - - - - key - text - true - 64 - - - - ttl - integer - -1 - true - 4 - - - - true - true - lock_id_index - - id - ascending - - - - - true - lock_key_index - - key - ascending - - - - - lock_ttl_index - - ttl - ascending - - - - - -
- - - - *dbprefix*comments - - - - - id - integer - 0 - true - true - 4 - 1 - - - - parent_id - integer - 0 - true - true - 4 - - - - topmost_parent_id - integer - 0 - true - true - 4 - - - - children_count - integer - 0 - true - true - 4 - - - - actor_type - text - - true - 64 - - - - actor_id - text - - true - 64 - - - - message - clob - - false - - - - verb - text - - false - 64 - - - - creation_timestamp - timestamp - - false - - - - latest_child_timestamp - timestamp - - false - - - - object_type - text - - true - 64 - - - - object_id - text - - true - 64 - - - - comments_parent_id_index - false - - parent_id - descending - - - - - comments_topmost_parent_id_idx - false - - topmost_parent_id - descending - - - - - comments_object_index - false - - object_type - ascending - - - object_id - ascending - - - creation_timestamp - descending - - - - - comments_actor_index - false - - actor_type - ascending - - - actor_id - ascending - - - - - -
- - - - *dbprefix*comments_read_markers - - - - - user_id - text - - true - 64 - - - - marker_datetime - timestamp - - false - - - - object_type - text - - true - 64 - - - - object_id - text - - true - 64 - - - - comments_marker_object_index - false - - object_type - ascending - - - object_id - ascending - - - - - comments_marker_index - true - - user_id - descending - - - object_type - ascending - - - object_id - ascending - - - - - -
- - - - *dbprefix*credentials - - - - - user - text - - false - 64 - - - - identifier - text - true - 64 - - - - credentials - clob - false - - - - credentials_user_id - true - true - - user - ascending - - - identifier - ascending - - - - - credentials_user - false - - user - ascending - - - - - -
- - - - *dbprefix*admin_sections - - - - - id - text - - false - 64 - - - - class - text - - true - 255 - - - - priority - integer - - true - 1 - - - - admin_sections_id_index - true - - id - ascending - - - - - admin_sections_class - true - - class - ascending - - - - -
- - - - *dbprefix*admin_settings - - - - - id - integer - 0 - true - 1 - 4 - - - - class - text - - true - 255 - - - - - section - text - - false - 64 - - - - priority - integer - - true - 1 - - - - admin_settings_id_index - true - - id - ascending - - - - - admin_settings_class - true - - class - ascending - - - - - admin_settings_section - false - - section - ascending - - - - -
- - - - *dbprefix*personal_sections - - - - - id - text - - false - 64 - - - - class - text - - true - 255 - - - - priority - integer - - true - 1 - - - - personal_sections_id_index - true - - id - ascending - - - - - personal_sections_class - true - - class - ascending - - - - -
- - - - *dbprefix*personal_settings - - - - - id - integer - 0 - true - 1 - 4 - - - - class - text - - true - 255 - - - - - section - text - - false - 64 - - - - priority - integer - - true - 1 - - - - personal_settings_id_index - true - - id - ascending - - - - - personal_settings_class - true - - class - ascending - - - - - personal_settings_section - false - - section - ascending - - - - -
- - - - *dbprefix*accounts - - - - uid - text - - true - 64 - - - data - clob - - true - - - - uid_index - true - true - - uid - ascending - - - - -
- -
diff --git a/lib/private/Setup.php b/lib/private/Setup.php index 5cd3c84ce9..f5bfca604a 100644 --- a/lib/private/Setup.php +++ b/lib/private/Setup.php @@ -282,8 +282,7 @@ class Setup { $class = self::$dbSetupClasses[$dbType]; /** @var \OC\Setup\AbstractDatabase $dbSetup */ - $dbSetup = new $class($l, 'db_structure.xml', $this->config, - $this->logger, $this->random); + $dbSetup = new $class($l, $this->config, $this->logger, $this->random); $error = array_merge($error, $dbSetup->validate($options)); // validate the data directory diff --git a/lib/private/Setup/AbstractDatabase.php b/lib/private/Setup/AbstractDatabase.php index 2fbec326a5..0e0981e077 100644 --- a/lib/private/Setup/AbstractDatabase.php +++ b/lib/private/Setup/AbstractDatabase.php @@ -38,8 +38,6 @@ abstract class AbstractDatabase { /** @var IL10N */ protected $trans; /** @var string */ - protected $dbDefinitionFile; - /** @var string */ protected $dbUser; /** @var string */ protected $dbPassword; @@ -58,9 +56,8 @@ abstract class AbstractDatabase { /** @var ISecureRandom */ protected $random; - public function __construct(IL10N $trans, $dbDefinitionFile, SystemConfig $config, ILogger $logger, ISecureRandom $random) { + public function __construct(IL10N $trans, SystemConfig $config, ILogger $logger, ISecureRandom $random) { $this->trans = $trans; - $this->dbDefinitionFile = $dbDefinitionFile; $this->config = $config; $this->logger = $logger; $this->random = $random; diff --git a/lib/private/Setup/MySQL.php b/lib/private/Setup/MySQL.php index b4ca02d2e8..d03e4858b6 100644 --- a/lib/private/Setup/MySQL.php +++ b/lib/private/Setup/MySQL.php @@ -51,11 +51,7 @@ class MySQL extends AbstractDatabase { //fill the database if needed $query='select count(*) from information_schema.tables where table_schema=? AND table_name = ?'; - $result = $connection->executeQuery($query, [$this->dbName, $this->tablePrefix.'users']); - $row = $result->fetch(); - if (!$row or $row['count(*)'] === '0') { - \OC_DB::createDbFromStructure($this->dbDefinitionFile); - } + $connection->executeQuery($query, [$this->dbName, $this->tablePrefix.'users']); } /** diff --git a/lib/private/Setup/OCI.php b/lib/private/Setup/OCI.php index 1bc6b08117..3051987917 100644 --- a/lib/private/Setup/OCI.php +++ b/lib/private/Setup/OCI.php @@ -165,14 +165,7 @@ class OCI extends AbstractDatabase { $entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '
'; $this->logger->warning( $entry, ['app' => 'setup.oci']); } - $result = oci_execute($stmt); - - if($result) { - $row = oci_fetch_row($stmt); - } - if(!$result or $row[0]==0) { - \OC_DB::createDbFromStructure($this->dbDefinitionFile); - } + oci_execute($stmt); } /** diff --git a/lib/private/Setup/PostgreSQL.php b/lib/private/Setup/PostgreSQL.php index 8267b06514..dbcb94d6d7 100644 --- a/lib/private/Setup/PostgreSQL.php +++ b/lib/private/Setup/PostgreSQL.php @@ -105,11 +105,6 @@ class PostgreSQL extends AbstractDatabase { throw new \OC\DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'), $this->trans->t('You need to enter details of an existing account.')); } - - - if (!$tablesSetup) { - \OC_DB::createDbFromStructure($this->dbDefinitionFile); - } } private function createDatabase(IDBConnection $connection) { diff --git a/lib/private/Setup/Sqlite.php b/lib/private/Setup/Sqlite.php index 87c0b82682..d95e70c8b0 100644 --- a/lib/private/Setup/Sqlite.php +++ b/lib/private/Setup/Sqlite.php @@ -41,6 +41,5 @@ class Sqlite extends AbstractDatabase { } //in case of sqlite, we can always fill the database error_log("creating sqlite db"); - \OC_DB::createDbFromStructure($this->dbDefinitionFile); } } From 5308bd3378c45a44a5e367a7c9d1b1f2573e62f2 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Tue, 18 Jul 2017 19:36:40 +0200 Subject: [PATCH 03/16] Fix autoloader Signed-off-by: Morris Jobke --- lib/composer/composer/autoload_classmap.php | 2 ++ lib/composer/composer/autoload_static.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 749b3949f6..c43aa6bb4f 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -426,6 +426,7 @@ return array( 'OC\\Core\\Command\\Db\\GenerateChangeScript' => $baseDir . '/core/Command/Db/GenerateChangeScript.php', 'OC\\Core\\Command\\Db\\Migrations\\ExecuteCommand' => $baseDir . '/core/Command/Db/Migrations/ExecuteCommand.php', 'OC\\Core\\Command\\Db\\Migrations\\GenerateCommand' => $baseDir . '/core/Command/Db/Migrations/GenerateCommand.php', + 'OC\\Core\\Command\\Db\\Migrations\\GenerateFromSchemaFileCommand' => $baseDir . '/core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php', 'OC\\Core\\Command\\Db\\Migrations\\MigrateCommand' => $baseDir . '/core/Command/Db/Migrations/MigrateCommand.php', 'OC\\Core\\Command\\Db\\Migrations\\StatusCommand' => $baseDir . '/core/Command/Db/Migrations/StatusCommand.php', 'OC\\Core\\Command\\Encryption\\ChangeKeyStorageRoot' => $baseDir . '/core/Command/Encryption/ChangeKeyStorageRoot.php', @@ -489,6 +490,7 @@ return array( 'OC\\Core\\Controller\\UserController' => $baseDir . '/core/Controller/UserController.php', 'OC\\Core\\Middleware\\TwoFactorMiddleware' => $baseDir . '/core/Middleware/TwoFactorMiddleware.php', 'OC\\Core\\Migrations\\Version13000Date20170705121758' => $baseDir . '/core/Migrations/Version13000Date20170705121758.php', + 'OC\\Core\\Migrations\\Version13000Date20170718121200' => $baseDir . '/core/Migrations/Version13000Date20170718121200.php', 'OC\\DB\\Adapter' => $baseDir . '/lib/private/DB/Adapter.php', 'OC\\DB\\AdapterMySQL' => $baseDir . '/lib/private/DB/AdapterMySQL.php', 'OC\\DB\\AdapterOCI8' => $baseDir . '/lib/private/DB/AdapterOCI8.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index d92045f6c5..e8ba105744 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -456,6 +456,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Core\\Command\\Db\\GenerateChangeScript' => __DIR__ . '/../../..' . '/core/Command/Db/GenerateChangeScript.php', 'OC\\Core\\Command\\Db\\Migrations\\ExecuteCommand' => __DIR__ . '/../../..' . '/core/Command/Db/Migrations/ExecuteCommand.php', 'OC\\Core\\Command\\Db\\Migrations\\GenerateCommand' => __DIR__ . '/../../..' . '/core/Command/Db/Migrations/GenerateCommand.php', + 'OC\\Core\\Command\\Db\\Migrations\\GenerateFromSchemaFileCommand' => __DIR__ . '/../../..' . '/core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php', 'OC\\Core\\Command\\Db\\Migrations\\MigrateCommand' => __DIR__ . '/../../..' . '/core/Command/Db/Migrations/MigrateCommand.php', 'OC\\Core\\Command\\Db\\Migrations\\StatusCommand' => __DIR__ . '/../../..' . '/core/Command/Db/Migrations/StatusCommand.php', 'OC\\Core\\Command\\Encryption\\ChangeKeyStorageRoot' => __DIR__ . '/../../..' . '/core/Command/Encryption/ChangeKeyStorageRoot.php', @@ -519,6 +520,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Core\\Controller\\UserController' => __DIR__ . '/../../..' . '/core/Controller/UserController.php', 'OC\\Core\\Middleware\\TwoFactorMiddleware' => __DIR__ . '/../../..' . '/core/Middleware/TwoFactorMiddleware.php', 'OC\\Core\\Migrations\\Version13000Date20170705121758' => __DIR__ . '/../../..' . '/core/Migrations/Version13000Date20170705121758.php', + 'OC\\Core\\Migrations\\Version13000Date20170718121200' => __DIR__ . '/../../..' . '/core/Migrations/Version13000Date20170718121200.php', 'OC\\DB\\Adapter' => __DIR__ . '/../../..' . '/lib/private/DB/Adapter.php', 'OC\\DB\\AdapterMySQL' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterMySQL.php', 'OC\\DB\\AdapterOCI8' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterOCI8.php', From 242c9ee06cdde73dfc3c0901393a0c7f30ae5680 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Jul 2017 10:59:09 +0200 Subject: [PATCH 04/16] No more root file Signed-off-by: Joas Schilling --- build/files-checker.php | 1 - 1 file changed, 1 deletion(-) diff --git a/build/files-checker.php b/build/files-checker.php index 4d4e64e361..66c44bd971 100644 --- a/build/files-checker.php +++ b/build/files-checker.php @@ -58,7 +58,6 @@ $expectedFiles = [ 'COPYING-README', 'core', 'cron.php', - 'db_structure.xml', 'index.html', 'index.php', 'issue_template.md', From 9307aaee498eae9fb0e1b5e802be88c2e572127d Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Jul 2017 11:17:04 +0200 Subject: [PATCH 05/16] Core is converted, so this is dead code Signed-off-by: Joas Schilling --- .../Migrations/GenerateFromSchemaFileCommand.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php b/core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php index 38f8d82b96..54a4d95738 100644 --- a/core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php +++ b/core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php @@ -65,17 +65,15 @@ class GenerateFromSchemaFileCommand extends GenerateCommand { return 1; } - $reader = new MDB2SchemaReader($this->config, $this->connection->getDatabasePlatform()); - $schema = new Schema(); - if ($appName === 'core') { - $reader->loadSchemaFromFile(\OC::$SERVERROOT . '/db_structure.xml', $schema); - } else { - if (!file_exists($this->appManager->getAppPath($appName) . '/appinfo/database.xml')) { - throw new \RuntimeException('App ' . $appName . ' does not have a database.xml file'); - } - $reader->loadSchemaFromFile($this->appManager->getAppPath($appName) . '/appinfo/database.xml', $schema); + $schemaFile = $this->appManager->getAppPath($appName) . '/appinfo/database.xml'; + if (!file_exists($schemaFile)) { + $output->writeln('App ' . $appName . ' does not have a database.xml file'); + return 2; } + $reader = new MDB2SchemaReader($this->config, $this->connection->getDatabasePlatform()); + $schema = new Schema(); + $reader->loadSchemaFromFile($schemaFile, $schema); $schemaBody = $this->schemaToMigration($schema); From 1d56b5276100bffa50d2fb575f498f297c5048d4 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Jul 2017 11:48:58 +0200 Subject: [PATCH 06/16] Use migrations on convert Signed-off-by: Joas Schilling --- core/Command/Db/ConvertType.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/core/Command/Db/ConvertType.php b/core/Command/Db/ConvertType.php index 16864e57db..7f17950ad6 100644 --- a/core/Command/Db/ConvertType.php +++ b/core/Command/Db/ConvertType.php @@ -28,6 +28,7 @@ namespace OC\Core\Command\Db; +use OC\DB\MigrationService; use OCP\DB\QueryBuilder\IQueryBuilder; use \OCP\IConfig; use OC\DB\Connection; @@ -219,12 +220,18 @@ class ConvertType extends Command implements CompletionAwareInterface { protected function createSchema(Connection $toDB, InputInterface $input, OutputInterface $output) { $output->writeln('Creating schema in new database'); + + $ms = new MigrationService('core', $toDB); + $ms->migrate(); // FIXME should only migrate to the current version? + $schemaManager = new \OC\DB\MDB2SchemaManager($toDB); - $schemaManager->createDbFromStructure(\OC::$SERVERROOT.'/db_structure.xml'); $apps = $input->getOption('all-apps') ? \OC_App::getAllApps() : \OC_App::getEnabledApps(); foreach($apps as $app) { if (file_exists(\OC_App::getAppPath($app).'/appinfo/database.xml')) { $schemaManager->createDbFromStructure(\OC_App::getAppPath($app).'/appinfo/database.xml'); + } else { + $ms = new MigrationService($app, $toDB); + $ms->migrate(); // FIXME should only migrate to the current version? } } } From 42ed7a18cc841d289b6bcc83885bf93165200e09 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Jul 2017 12:12:38 +0200 Subject: [PATCH 07/16] Skip migrations table because it was already done when creating the schema Signed-off-by: Joas Schilling --- core/Command/Db/ConvertType.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/Command/Db/ConvertType.php b/core/Command/Db/ConvertType.php index 7f17950ad6..554ab6cd21 100644 --- a/core/Command/Db/ConvertType.php +++ b/core/Command/Db/ConvertType.php @@ -277,6 +277,12 @@ class ConvertType extends Command implements CompletionAwareInterface { * @suppress SqlInjectionChecker */ protected function copyTable(Connection $fromDB, Connection $toDB, $table, InputInterface $input, OutputInterface $output) { + if ($table === $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(); From 3fedfe67b9d89a1d83c40b6290c88a304da1c321 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Jul 2017 12:13:23 +0200 Subject: [PATCH 08/16] Use default connection parameters for utf8 4byte support Signed-off-by: Joas Schilling --- core/Command/Db/ConvertType.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/Command/Db/ConvertType.php b/core/Command/Db/ConvertType.php index 554ab6cd21..9b8284c930 100644 --- a/core/Command/Db/ConvertType.php +++ b/core/Command/Db/ConvertType.php @@ -238,13 +238,13 @@ class ConvertType extends Command implements CompletionAwareInterface { protected function getToDBConnection(InputInterface $input, OutputInterface $output) { $type = $input->getArgument('type'); - $connectionParams = array( + $connectionParams = $this->connectionFactory->createConnectionParams(); + $connectionParams = array_merge($connectionParams, [ 'host' => $input->getArgument('hostname'), 'user' => $input->getArgument('username'), 'password' => $input->getOption('password'), 'dbname' => $input->getArgument('database'), - 'tablePrefix' => $this->config->getSystemValue('dbtableprefix', 'oc_'), - ); + ]); if ($input->getOption('port')) { $connectionParams['port'] = $input->getOption('port'); } From 0a0dbbdf15d30951d909924b6e3f3b2bcc093017 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Jul 2017 12:14:42 +0200 Subject: [PATCH 09/16] Remove generate change script which doesnt work with migrations anymore Signed-off-by: Joas Schilling --- core/Command/Db/GenerateChangeScript.php | 89 --------------------- core/register_command.php | 1 - lib/composer/composer/autoload_classmap.php | 1 - lib/composer/composer/autoload_static.php | 1 - 4 files changed, 92 deletions(-) delete mode 100644 core/Command/Db/GenerateChangeScript.php diff --git a/core/Command/Db/GenerateChangeScript.php b/core/Command/Db/GenerateChangeScript.php deleted file mode 100644 index bbe8d29958..0000000000 --- a/core/Command/Db/GenerateChangeScript.php +++ /dev/null @@ -1,89 +0,0 @@ - - * @author Thomas Müller - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see - * - */ - -namespace OC\Core\Command\Db; - -use Stecman\Component\Symfony\Console\BashCompletion\Completion; -use Stecman\Component\Symfony\Console\BashCompletion\Completion\CompletionAwareInterface; -use Stecman\Component\Symfony\Console\BashCompletion\Completion\ShellPathCompletion; -use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext; -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; - -class GenerateChangeScript extends Command implements CompletionAwareInterface { - protected function configure() { - $this - ->setName('db:generate-change-script') - ->setDescription('generates the change script from the current connected db to db_structure.xml') - ->addArgument( - 'schema-xml', - InputArgument::OPTIONAL, - 'the schema xml to be used as target schema', - \OC::$SERVERROOT . '/db_structure.xml' - ) - ; - } - - protected function execute(InputInterface $input, OutputInterface $output) { - - $file = $input->getArgument('schema-xml'); - - $schemaManager = new \OC\DB\MDB2SchemaManager(\OC::$server->getDatabaseConnection()); - - try { - $result = $schemaManager->updateDbFromStructure($file, true); - $output->writeln($result); - } catch (\Exception $e) { - $output->writeln('Failed to update database structure ('.$e.')'); - } - - } - - /** - * @param string $optionName - * @param CompletionContext $context - * @return string[] - */ - public function completeOptionValues($optionName, CompletionContext $context) { - return []; - } - - /** - * @param string $argumentName - * @param CompletionContext $context - * @return string[] - */ - public function completeArgumentValues($argumentName, CompletionContext $context) { - if ($argumentName === 'schema-xml') { - $helper = new ShellPathCompletion( - $this->getName(), - 'schema-xml', - Completion::TYPE_ARGUMENT - ); - return $helper->run(); - } - return []; - } -} diff --git a/core/register_command.php b/core/register_command.php index c65ff8d006..fd693729a7 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -82,7 +82,6 @@ if (\OC::$server->getConfig()->getSystemValue('installed', false)) { $application->add(new OC\Core\Command\Config\System\GetConfig(\OC::$server->getSystemConfig())); $application->add(new OC\Core\Command\Config\System\SetConfig(\OC::$server->getSystemConfig())); - $application->add(new OC\Core\Command\Db\GenerateChangeScript()); $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->getLogger())); $application->add(new OC\Core\Command\Db\Migrations\StatusCommand(\OC::$server->getDatabaseConnection())); diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index c43aa6bb4f..0923182470 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -423,7 +423,6 @@ return array( 'OC\\Core\\Command\\Config\\System\\SetConfig' => $baseDir . '/core/Command/Config/System/SetConfig.php', 'OC\\Core\\Command\\Db\\ConvertMysqlToMB4' => $baseDir . '/core/Command/Db/ConvertMysqlToMB4.php', 'OC\\Core\\Command\\Db\\ConvertType' => $baseDir . '/core/Command/Db/ConvertType.php', - 'OC\\Core\\Command\\Db\\GenerateChangeScript' => $baseDir . '/core/Command/Db/GenerateChangeScript.php', 'OC\\Core\\Command\\Db\\Migrations\\ExecuteCommand' => $baseDir . '/core/Command/Db/Migrations/ExecuteCommand.php', 'OC\\Core\\Command\\Db\\Migrations\\GenerateCommand' => $baseDir . '/core/Command/Db/Migrations/GenerateCommand.php', 'OC\\Core\\Command\\Db\\Migrations\\GenerateFromSchemaFileCommand' => $baseDir . '/core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index e8ba105744..8f23eb53ec 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -453,7 +453,6 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Core\\Command\\Config\\System\\SetConfig' => __DIR__ . '/../../..' . '/core/Command/Config/System/SetConfig.php', 'OC\\Core\\Command\\Db\\ConvertMysqlToMB4' => __DIR__ . '/../../..' . '/core/Command/Db/ConvertMysqlToMB4.php', 'OC\\Core\\Command\\Db\\ConvertType' => __DIR__ . '/../../..' . '/core/Command/Db/ConvertType.php', - 'OC\\Core\\Command\\Db\\GenerateChangeScript' => __DIR__ . '/../../..' . '/core/Command/Db/GenerateChangeScript.php', 'OC\\Core\\Command\\Db\\Migrations\\ExecuteCommand' => __DIR__ . '/../../..' . '/core/Command/Db/Migrations/ExecuteCommand.php', 'OC\\Core\\Command\\Db\\Migrations\\GenerateCommand' => __DIR__ . '/../../..' . '/core/Command/Db/Migrations/GenerateCommand.php', 'OC\\Core\\Command\\Db\\Migrations\\GenerateFromSchemaFileCommand' => __DIR__ . '/../../..' . '/core/Command/Db/Migrations/GenerateFromSchemaFileCommand.php', From 10d7cbb71f89b1e5e39a894bda1b0701760224a0 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Jul 2017 13:15:32 +0200 Subject: [PATCH 10/16] 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 From 1b7c1ad5c0c3b28efdfbbc0f4e8730dda9963317 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Jul 2017 13:18:10 +0200 Subject: [PATCH 11/16] Only migrate to the current state Signed-off-by: Joas Schilling --- core/Command/Db/ConvertType.php | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/core/Command/Db/ConvertType.php b/core/Command/Db/ConvertType.php index f05014936f..cccba47b4e 100644 --- a/core/Command/Db/ConvertType.php +++ b/core/Command/Db/ConvertType.php @@ -193,7 +193,7 @@ class ConvertType extends Command implements CompletionAwareInterface { $this->clearSchema($toDB, $input, $output); } - $this->createSchema($toDB, $input, $output); + $this->createSchema($fromDB, $toDB, $input, $output); $toTables = $this->getTables($toDB); $fromTables = $this->getTables($fromDB); @@ -220,11 +220,15 @@ class ConvertType extends Command implements CompletionAwareInterface { $this->convertDB($fromDB, $toDB, $intersectingTables, $input, $output); } - protected function createSchema(Connection $toDB, InputInterface $input, OutputInterface $output) { + protected function createSchema(Connection $fromDB, Connection $toDB, InputInterface $input, OutputInterface $output) { $output->writeln('Creating schema in new database'); - $ms = new MigrationService('core', $toDB); - $ms->migrate(); // FIXME should only migrate to the current version? + $fromMS = new MigrationService('core', $fromDB); + $currentMigration = $fromMS->getMigration('current'); + if ($currentMigration !== '0') { + $toMS = new MigrationService('core', $toDB); + $toMS->migrate($currentMigration); + } $schemaManager = new \OC\DB\MDB2SchemaManager($toDB); $apps = $input->getOption('all-apps') ? \OC_App::getAllApps() : \OC_App::getEnabledApps(); @@ -232,8 +236,14 @@ class ConvertType extends Command implements CompletionAwareInterface { if (file_exists(\OC_App::getAppPath($app).'/appinfo/database.xml')) { $schemaManager->createDbFromStructure(\OC_App::getAppPath($app).'/appinfo/database.xml'); } else { - $ms = new MigrationService($app, $toDB); - $ms->migrate(); // FIXME should only migrate to the current version? + // Make sure autoloading works... + \OC_App::loadApp($app); + $fromMS = new MigrationService($app, $fromDB); + $currentMigration = $fromMS->getMigration('current'); + if ($currentMigration !== '0') { + $toMS = new MigrationService($app, $toDB); + $toMS->migrate($currentMigration); + } } } } From e023899078d66084feb6982a347c4d28dac09192 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Jul 2017 13:20:24 +0200 Subject: [PATCH 12/16] Always order by all values, to make sure all entries are copied correctly Signed-off-by: Joas Schilling --- core/Command/Db/ConvertType.php | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/core/Command/Db/ConvertType.php b/core/Command/Db/ConvertType.php index cccba47b4e..81b2988b9d 100644 --- a/core/Command/Db/ConvertType.php +++ b/core/Command/Db/ConvertType.php @@ -324,18 +324,13 @@ class ConvertType extends Command implements CompletionAwareInterface { $orderColumns = $table->getPrimaryKeyColumns(); } catch (DBALException $e) { $orderColumns = []; - } - foreach ($table->getIndexes() as $index) { - if ($index->isUnique()) { - $orderColumns = array_merge($orderColumns, $index->getUnquotedColumns()); + foreach ($table->getColumns() as $column) { + $orderColumns[] = $column->getName(); } } - $orderColumns = array_unique($orderColumns); - if (!empty($orderColumns)) { - foreach ($orderColumns as $column) { - $query->addOrderBy($column); - } + foreach ($orderColumns as $column) { + $query->addOrderBy($column); } $insertQuery = $toDB->getQueryBuilder(); From 087138f2280a95ed677be82d1420e32793227cd7 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Jul 2017 13:23:14 +0200 Subject: [PATCH 13/16] use template placeholders instead of html Signed-off-by: Joas Schilling --- core/Command/Db/Migrations/GenerateCommand.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/Command/Db/Migrations/GenerateCommand.php b/core/Command/Db/Migrations/GenerateCommand.php index f8a992940f..4db82d6eff 100644 --- a/core/Command/Db/Migrations/GenerateCommand.php +++ b/core/Command/Db/Migrations/GenerateCommand.php @@ -38,7 +38,7 @@ class GenerateCommand extends Command { protected static $_templateSimple = '; +namespace {{ extends SimpleMigrationStep { +class {{classname}} extends SimpleMigrationStep { /** * @param IOutput $output @@ -66,7 +66,7 @@ class extends SimpleMigrationStep { * @since 13.0.0 */ public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { - +{{schemabody}} } /** @@ -133,9 +133,9 @@ class extends SimpleMigrationStep { $placeHolders = [ - '', - '', - '', + '{{namespace}}', + '{{classname}}', + '{{schemabody}}', ]; $replacements = [ $ms->getMigrationsNamespace(), From b729cc2a02e3bb9a1010b6dee27292d34c2ba8a4 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Jul 2017 16:17:46 +0200 Subject: [PATCH 14/16] Add *lob support for all tables Signed-off-by: Joas Schilling --- core/Command/Db/ConvertType.php | 35 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/core/Command/Db/ConvertType.php b/core/Command/Db/ConvertType.php index 81b2988b9d..a783952293 100644 --- a/core/Command/Db/ConvertType.php +++ b/core/Command/Db/ConvertType.php @@ -30,6 +30,7 @@ namespace OC\Core\Command\Db; use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Schema\Table; +use Doctrine\DBAL\Types\Type; use OC\DB\MigrationService; use OCP\DB\QueryBuilder\IQueryBuilder; use \OCP\IConfig; @@ -353,7 +354,7 @@ class ConvertType extends Command implements CompletionAwareInterface { } foreach ($row as $key => $value) { - $type = $this->getColumnType($table->getName(), $key); + $type = $this->getColumnType($table, $key); if ($type !== false) { $insertQuery->setParameter($key, $value, $type); } else { @@ -367,24 +368,24 @@ class ConvertType extends Command implements CompletionAwareInterface { $progress->finish(); } - protected function getColumnType($table, $column) { - if (isset($this->columnTypes[$table][$column])) { - return $this->columnTypes[$table][$column]; - } - $prefix = $this->config->getSystemValue('dbtableprefix', 'oc_'); - - $this->columnTypes[$table][$column] = false; - - if ($table === $prefix . 'cards' && $column === 'carddata') { - $this->columnTypes[$table][$column] = IQueryBuilder::PARAM_LOB; - } else if ($column === 'calendardata') { - if ($table === $prefix . 'calendarobjects' || - $table === $prefix . 'schedulingobjects') { - $this->columnTypes[$table][$column] = IQueryBuilder::PARAM_LOB; - } + protected function getColumnType(Table $table, $columnName) { + $tableName = $table->getName(); + if (isset($this->columnTypes[$tableName][$columnName])) { + return $this->columnTypes[$tableName][$columnName]; } - return $this->columnTypes[$table][$column]; + $type = $table->getColumn($columnName)->getType()->getName(); + + switch ($type) { + case Type::BLOB: + case Type::TEXT: + $this->columnTypes[$tableName][$columnName] = IQueryBuilder::PARAM_LOB; + break; + default: + $this->columnTypes[$tableName][$columnName] = false; + } + + return $this->columnTypes[$tableName][$columnName]; } protected function convertDB(Connection $fromDB, Connection $toDB, array $tables, InputInterface $input, OutputInterface $output) { From 41fca6c852c08e7e74ae2ceea8eadeda7a1348b1 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Jul 2017 16:18:11 +0200 Subject: [PATCH 15/16] "Only variables must be passed by reference" Signed-off-by: Joas Schilling --- lib/private/DB/MigrationService.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/private/DB/MigrationService.php b/lib/private/DB/MigrationService.php index 92041b5e32..45f6aee83f 100644 --- a/lib/private/DB/MigrationService.php +++ b/lib/private/DB/MigrationService.php @@ -284,7 +284,8 @@ class MigrationService { case 'latest': $this->ensureMigrationsAreLoaded(); - return @end($this->getAvailableVersions()); + $migrations = $this->getAvailableVersions(); + return @end($migrations); } return '0'; } @@ -316,7 +317,8 @@ class MigrationService { if (count($m) === 0) { return '0'; } - return @end(array_values($m)); + $migrations = array_values($m); + return @end($migrations); } /** From d254797f561b0f7a2f3feeaa8bb868ad2d3c74be Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 19 Jul 2017 16:18:30 +0200 Subject: [PATCH 16/16] Trigger update to run the migration Signed-off-by: Joas Schilling --- version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.php b/version.php index d9e26eafce..649c8ae738 100644 --- a/version.php +++ b/version.php @@ -26,7 +26,7 @@ // between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel // when updating major/minor version number. -$OC_Version = array(13, 0, 0, 1); +$OC_Version = array(13, 0, 0, 2); // The human readable string $OC_VersionString = '13.0.0 alpha';