Loading core/modules/mysql/src/Driver/Database/mysql/Schema.php +18 −1 Original line number Diff line number Diff line Loading @@ -2,12 +2,15 @@ namespace Drupal\mysql\Driver\Database\mysql; use Drupal\Core\Database\DatabaseExceptionWrapper; use Drupal\Core\Database\SchemaException; use Drupal\Core\Database\SchemaObjectExistsException; use Drupal\Core\Database\SchemaObjectDoesNotExistException; use Drupal\Core\Database\Schema as DatabaseSchema; use Drupal\Component\Utility\Unicode; // cspell:ignore gipk /** * @addtogroup schemaapi * @{ Loading Loading @@ -426,7 +429,21 @@ public function addField($table, $field, $spec, $keys_new = []) { $query .= ', ADD ' . implode(', ADD ', $keys_sql); } try { $this->connection->query($query); } catch (DatabaseExceptionWrapper $e) { // MySQL error number 4111 (ER_DROP_PK_COLUMN_TO_DROP_GIPK) indicates that // when dropping and adding a primary key, the generated invisible primary // key (GIPK) column must also be dropped. if (isset($e->getPrevious()->errorInfo[1]) && $e->getPrevious()->errorInfo[1] === 4111 && isset($keys_new['primary key']) && $this->indexExists($table, 'PRIMARY') && $this->findPrimaryKeyColumns($table) === ['my_row_id']) { $this->connection->query($query . ', DROP COLUMN [my_row_id]'); } else { throw $e; } } if (isset($spec['initial_from_field'])) { if (isset($spec['initial'])) { $expression = 'COALESCE(' . $spec['initial_from_field'] . ', :default_initial_value)'; Loading core/modules/mysql/tests/src/Kernel/mysql/SchemaTest.php +29 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ namespace Drupal\Tests\mysql\Kernel\mysql; use Drupal\Component\Utility\Unicode; use Drupal\Core\Database\DatabaseExceptionWrapper; use Drupal\Core\Database\Exception\SchemaTableColumnSizeTooLargeException; use Drupal\Core\Database\Exception\SchemaTableKeyTooLargeException; use Drupal\Core\Database\SchemaException; Loading Loading @@ -311,4 +312,32 @@ public function testSchemaTableColumnSizeTooLargeException(): void { ]); } /** * Tests adding a primary key when sql_generate_invisible_primary_key is on. */ public function testGeneratedInvisiblePrimaryKey(): void { $is_maria = method_exists($this->connection, 'isMariaDb') && $this->connection->isMariaDb(); if ($this->connection->databaseType() !== 'mysql' || $is_maria || version_compare($this->connection->version(), '8.0.30', '<')) { $this->markTestSkipped('This test only runs on MySQL 8.0.30 and above'); } try { $this->connection->query("SET sql_generate_invisible_primary_key = 1;")->execute(); } catch (DatabaseExceptionWrapper $e) { $this->markTestSkipped('This test requires the SESSION_VARIABLES_ADMIN privilege.'); } $this->schema->createTable('test_primary_key', [ 'fields' => [ 'foo' => [ 'type' => 'varchar', 'length' => 1, ], ], ]); $this->schema->addField('test_primary_key', 'id', [ 'type' => 'serial', 'not null' => TRUE, ], ['primary key' => ['id']]); } } Loading
core/modules/mysql/src/Driver/Database/mysql/Schema.php +18 −1 Original line number Diff line number Diff line Loading @@ -2,12 +2,15 @@ namespace Drupal\mysql\Driver\Database\mysql; use Drupal\Core\Database\DatabaseExceptionWrapper; use Drupal\Core\Database\SchemaException; use Drupal\Core\Database\SchemaObjectExistsException; use Drupal\Core\Database\SchemaObjectDoesNotExistException; use Drupal\Core\Database\Schema as DatabaseSchema; use Drupal\Component\Utility\Unicode; // cspell:ignore gipk /** * @addtogroup schemaapi * @{ Loading Loading @@ -426,7 +429,21 @@ public function addField($table, $field, $spec, $keys_new = []) { $query .= ', ADD ' . implode(', ADD ', $keys_sql); } try { $this->connection->query($query); } catch (DatabaseExceptionWrapper $e) { // MySQL error number 4111 (ER_DROP_PK_COLUMN_TO_DROP_GIPK) indicates that // when dropping and adding a primary key, the generated invisible primary // key (GIPK) column must also be dropped. if (isset($e->getPrevious()->errorInfo[1]) && $e->getPrevious()->errorInfo[1] === 4111 && isset($keys_new['primary key']) && $this->indexExists($table, 'PRIMARY') && $this->findPrimaryKeyColumns($table) === ['my_row_id']) { $this->connection->query($query . ', DROP COLUMN [my_row_id]'); } else { throw $e; } } if (isset($spec['initial_from_field'])) { if (isset($spec['initial'])) { $expression = 'COALESCE(' . $spec['initial_from_field'] . ', :default_initial_value)'; Loading
core/modules/mysql/tests/src/Kernel/mysql/SchemaTest.php +29 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ namespace Drupal\Tests\mysql\Kernel\mysql; use Drupal\Component\Utility\Unicode; use Drupal\Core\Database\DatabaseExceptionWrapper; use Drupal\Core\Database\Exception\SchemaTableColumnSizeTooLargeException; use Drupal\Core\Database\Exception\SchemaTableKeyTooLargeException; use Drupal\Core\Database\SchemaException; Loading Loading @@ -311,4 +312,32 @@ public function testSchemaTableColumnSizeTooLargeException(): void { ]); } /** * Tests adding a primary key when sql_generate_invisible_primary_key is on. */ public function testGeneratedInvisiblePrimaryKey(): void { $is_maria = method_exists($this->connection, 'isMariaDb') && $this->connection->isMariaDb(); if ($this->connection->databaseType() !== 'mysql' || $is_maria || version_compare($this->connection->version(), '8.0.30', '<')) { $this->markTestSkipped('This test only runs on MySQL 8.0.30 and above'); } try { $this->connection->query("SET sql_generate_invisible_primary_key = 1;")->execute(); } catch (DatabaseExceptionWrapper $e) { $this->markTestSkipped('This test requires the SESSION_VARIABLES_ADMIN privilege.'); } $this->schema->createTable('test_primary_key', [ 'fields' => [ 'foo' => [ 'type' => 'varchar', 'length' => 1, ], ], ]); $this->schema->addField('test_primary_key', 'id', [ 'type' => 'serial', 'not null' => TRUE, ], ['primary key' => ['id']]); } }