From 15cf8e8e32218c70da8bf48e22d8b62fe4e0451c Mon Sep 17 00:00:00 2001 From: gggeek Date: Mon, 2 Nov 2020 12:59:11 +0000 Subject: [PATCH] Issue #176 WIP --- Core/StorageHandler/Database/Context.php | 16 ++++++++++++-- Core/StorageHandler/Database/Migration.php | 19 ++++++++++++++--- Core/StorageHandler/Database/TableStorage.php | 21 +++++++++++++++++-- Resources/config/services.yml | 13 ++++++++++-- 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/Core/StorageHandler/Database/Context.php b/Core/StorageHandler/Database/Context.php index 797a5670..deb58cca 100644 --- a/Core/StorageHandler/Database/Context.php +++ b/Core/StorageHandler/Database/Context.php @@ -2,8 +2,9 @@ namespace Kaliop\eZMigrationBundle\Core\StorageHandler\Database; -use Kaliop\eZMigrationBundle\API\ContextStorageHandlerInterface; use Doctrine\DBAL\Schema\Schema; +use eZ\Publish\Core\Persistence\Database\QueryException; +use Kaliop\eZMigrationBundle\API\ContextStorageHandlerInterface; class Context extends TableStorage implements ContextStorageHandlerInterface { @@ -117,8 +118,19 @@ public function createTable() $t->addColumn('insertion_date', 'integer'); $t->setPrimaryKey(array('migration')); + $this->injectTableCreationOptions($t); + foreach ($schema->toSql($dbPlatform) as $sql) { - $this->dbHandler->exec($sql); + try { + $this->dbHandler->exec($sql); + } catch(QueryException $e) { + // work around limitations in both Mysql and Doctrine + // @see https://github.com/kaliop-uk/ezmigrationbundle/issues/176 + if (strpos($e->getMessage(), '1071 Specified key was too long; max key length is 767 bytes') !== false && + strpos($sql, 'PRIMARY KEY(migration)') !== false) { + $this->dbHandler->exec(str_replace('PRIMARY KEY(migration)', 'PRIMARY KEY(migration(191))', $sql)); + } + } } } diff --git a/Core/StorageHandler/Database/Migration.php b/Core/StorageHandler/Database/Migration.php index 6eecf174..6b61273e 100644 --- a/Core/StorageHandler/Database/Migration.php +++ b/Core/StorageHandler/Database/Migration.php @@ -5,6 +5,7 @@ use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use Doctrine\DBAL\Schema\Schema; use eZ\Publish\Core\Persistence\Database\DatabaseHandler; +use eZ\Publish\Core\Persistence\Database\QueryException; use eZ\Publish\Core\Persistence\Database\SelectQuery; use Kaliop\eZMigrationBundle\API\StorageHandlerInterface; use Kaliop\eZMigrationBundle\API\Collection\MigrationCollection; @@ -26,11 +27,12 @@ class Migration extends TableStorage implements StorageHandlerInterface * @param DatabaseHandler $dbHandler * @param string $tableNameParameter * @param ConfigResolverInterface $configResolver + * @param array $tableCreationOptions * @throws \Exception */ - public function __construct(DatabaseHandler $dbHandler, $tableNameParameter = 'kaliop_migrations', ConfigResolverInterface $configResolver = null) + public function __construct(DatabaseHandler $dbHandler, $tableNameParameter = 'kaliop_migrations', ConfigResolverInterface $configResolver = null, $tableCreationOptions = array()) { - parent::__construct($dbHandler, $tableNameParameter, $configResolver); + parent::__construct($dbHandler, $tableNameParameter, $configResolver, $tableCreationOptions); } /** @@ -427,8 +429,19 @@ public function createTable() // and 767 bytes can be either 255 chars or 191 chars depending on charset utf8 or utf8mb4... //$t->addIndex(array('path')); + $this->injectTableCreationOptions($t); + foreach ($schema->toSql($dbPlatform) as $sql) { - $this->dbHandler->exec($sql); + try { + $this->dbHandler->exec($sql); + } catch(QueryException $e) { + // work around limitations in both Mysql and Doctrine + // @see https://github.com/kaliop-uk/ezmigrationbundle/issues/176 + if (strpos($e->getMessage(), '1071 Specified key was too long; max key length is 767 bytes') !== false && + strpos($sql, 'PRIMARY KEY(migration)') !== false) { + $this->dbHandler->exec(str_replace('PRIMARY KEY(migration)', 'PRIMARY KEY(migration(191))', $sql)); + } + } } } diff --git a/Core/StorageHandler/Database/TableStorage.php b/Core/StorageHandler/Database/TableStorage.php index 0dffb70d..22d67af3 100644 --- a/Core/StorageHandler/Database/TableStorage.php +++ b/Core/StorageHandler/Database/TableStorage.php @@ -2,6 +2,7 @@ namespace Kaliop\eZMigrationBundle\Core\StorageHandler\Database; +use Doctrine\DBAL\Schema\Table; use eZ\Publish\Core\Persistence\Database\DatabaseHandler; use Kaliop\eZMigrationBundle\API\ConfigResolverInterface; @@ -27,20 +28,36 @@ abstract class TableStorage */ protected $tableExists = false; + /** @var array $tableCreationOptions */ + protected $tableCreationOptions; + /** * @param DatabaseHandler $dbHandler * @param string $tableNameParameter name of table when $configResolver is null, name of parameter otherwise * @param ConfigResolverInterface $configResolver + * @param array $tableCreationOptions * @throws \Exception */ - public function __construct(DatabaseHandler $dbHandler, $tableNameParameter, ConfigResolverInterface $configResolver = null) + public function __construct(DatabaseHandler $dbHandler, $tableNameParameter, ConfigResolverInterface $configResolver = null, $tableCreationOptions = array()) { $this->dbHandler = $dbHandler; $this->tableName = $configResolver ? $configResolver->getParameter($tableNameParameter) : $tableNameParameter; + $this->tableCreationOptions = $tableCreationOptions; } abstract function createTable(); + /** + * To be called from createTable to add to table definitions the common options (storage engine, charset, etc...) + * @param Table $table + */ + protected function injectTableCreationOptions(Table $table) + { + foreach($this->tableCreationOptions as $key => $value) { + $table->addOption($key, $value); + } + } + /** * @return mixed */ @@ -112,4 +129,4 @@ public function truncate() $this->dbHandler->exec('TRUNCATE ' . $this->tableName); } } -} \ No newline at end of file +} diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 4af86510..569babfb 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -15,10 +15,10 @@ parameters: # ez_migration_bundle..context_table_name ez_migration_bundle.context_table_name: 'kaliop_migrations_contexts' - # Used to discriminate valid migration definitions + # Used to discriminate valid migration definitions (for SQL migrations) ez_migration_bundle.valid_databases: # names have to correspond to doctrine 'platform', short of version numbers and lowercase - # NB: this does NOT mean that eZPublish supports all of them :-) + # NB: this does NOT mean that eZPublish supports all of them :-) By default it supports only mysql and postgresql... - 'mysql' - 'postgresql' - 'oracle' @@ -27,6 +27,13 @@ parameters: - 'sqlserver' - 'sqlanywhere' + # Character set used for the migration bundle database tables. Only used by the MySQL Doctrine driver apparently. + # Due to the Doctrine DB Schema Manager in use, this can not be set to null to mean 'use the default charset of the database'). + # It is a good idea to set it to the same character set used by eZP tables, even though at the moment there are no + # queries doing joins between migration tables and eZP tables. + # eZPlatform uses utf8mb4 charset as default, whereas eZPublish used utf8 + ez_migration_bundle.database_charset: 'utf8mb4' + # This is by default the max value for a 16-bit integer, which is what SOLR accepts as maximum nuber-of-results # limitation for its queries. # However, in multi-core configurations, you have to divide this most likely by the number of cores, or you will get @@ -197,6 +204,7 @@ services: - '@ezpublish.connection' - 'ez_migration_bundle.table_name' - '@ez_migration_bundle.helper.config.resolver' + - { charset: '%ez_migration_bundle.database_charset%' } ez_migration_bundle.context_storage_handler: alias: ez_migration_bundle.context_storage_handler.database @@ -207,6 +215,7 @@ services: - '@ezpublish.connection' - 'ez_migration_bundle.context_table_name' - '@ez_migration_bundle.helper.config.resolver' + - { charset: '%ez_migration_bundle.database_charset%' } ### executors