diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php index ecfa56409a..29c6aebb41 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php @@ -1370,13 +1370,8 @@ protected function createSharedTableSchema(FieldStorageDefinitionInterface $stor $new_keys = ['primary key' => $schema[$table_name]['primary key']]; // If the field is part of a primary key, it might be a serial - // field. Serial fields are incorrectly stored as integer fields - // in the field schema, so we adapt the schema here manually. - // @todo Remove this in - // https://www.drupal.org/project/drupal/issues/2928906 - $base_table_serial = ($created_field_name === $this->entityType->getKey('id')) && ($table_name === $this->storage->getBaseTable()); - $revision_table_serial = ($created_field_name === $this->entityType->getKey('revision')) && ($table_name === $this->storage->getRevisionTable()); - if (($specifier['type'] === 'int') && ($base_table_serial || $revision_table_serial)) { + // field. + if (($specifier['type'] === 'int') && $this->isSerialField($schema[$table_name], $table_name, $created_field_name)) { $specifier['type'] = 'serial'; } } @@ -1682,6 +1677,21 @@ protected function updateSharedTableSchema(FieldStorageDefinitionInterface $stor // Check if the field is part of the primary keys. if (isset($entity_schema[$table_name]['primary key']) && array_intersect($column_names, $entity_schema[$table_name]['primary key'])) { $schema_handler->addPrimaryKey($table_name, $entity_schema[$table_name]['primary key']); + + // If the field being updated is a serial field, it will have + // been changed to an integer field by + // SqlContentEntityStorageSchema::dropPrimaryKey() above. + // Convert it back now that the primary key has been recreated. + if ($this->isSerialField($schema[$table_name], $table_name, $updated_field_name)) { + foreach ($schema[$table_name]['primary key'] as $column_name) { + $spec = $schema[$table_name]['fields'][$column_name]; + if ($spec['type'] === 'int') { + $spec['type'] = 'serial'; + $schema_handler->changeField($table_name, $column_name, $column_name, $spec); + } + } + } + break; } } @@ -2439,13 +2449,7 @@ private function dropPrimaryKey(FieldStorageDefinitionInterface $storage_definit // Dropping a primary key must not leave a serial key, so we need to // change any serial field to integer first. $field_name = $storage_definition->getName(); - // Serial fields are incorrectly stored as integer fields in the field - // schema, so we explicitly check the conditions for marking it serial. - // @todo Remove this in - // https://www.drupal.org/project/drupal/issues/2928906 - $base_table_serial = ($field_name === $this->entityType->getKey('id')) && ($table_name === $this->storage->getBaseTable()); - $revision_table_serial = ($field_name === $this->entityType->getKey('revision')) && ($table_name === $this->storage->getRevisionTable()); - if ($base_table_serial || $revision_table_serial) { + if ($this->isSerialField($schema, $table_name, $field_name)) { foreach ($schema['primary key'] as $column_name) { if ($schema['fields'][$column_name]['type'] === 'int') { $schema_handler->changeField($table_name, $column_name, $column_name, $schema['fields'][$column_name]); @@ -2456,4 +2460,38 @@ private function dropPrimaryKey(FieldStorageDefinitionInterface $storage_definit } } + /** + * Checks whether the a field is a serial field in a given table. + * + * Because the field schema is incorrectly stored as 'int' we have to manually + * call SqlContentEntityStorageSchema::processIdentifierSchema() assuming the + * conditions are correct. + * + * @param array $schema + * The table schema. + * @param $table_name + * The table name. + * @param $field_name + * The field name. + * + * @return bool + * TRUE if the field is a serial field in the given table; FALSE otherwise. + * + * @internal + * + * @todo Remove this in https://www.drupal.org/project/drupal/issues/2928906 + */ + private function isSerialField(array $schema, $table_name, $field_name) { + // The ID field is serial in the base table. + $is_base_table = ($table_name === $this->storage->getBaseTable()); + $is_revision_table = ($table_name === $this->storage->getRevisionTable()); + $is_id = ($field_name === $this->entityType->getKey('id')); + $is_revision_id = ($field_name === $this->entityType->getKey('revision')); + if (($is_base_table && $is_id) || ($is_revision_table && $is_revision_id)) { + $this->processIdentifierSchema($schema, $field_name); + return $schema['fields'][$field_name]['type'] === 'serial'; + } + return FALSE; + } + }