diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php index 8273bb6..ecc1ee7 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php @@ -1500,7 +1500,7 @@ public function onFieldStorageDefinitionDelete(FieldStorageDefinitionInterface $ $this->entityManager->getLastInstalledFieldStorageDefinitions($this->entityType->id()) ); - // @todo Remove the FieldStorageConfigInterface check when nonconfigurable + // @todo Remove the FieldStorageConfigInterface check when non-configurable // fields support purging: https://www.drupal.org/node/2282119. if ($storage_definition instanceof FieldStorageConfigInterface && $table_mapping->requiresDedicatedTableStorage($storage_definition)) { // Mark all data associated with the field for deletion. diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php index 90c3469..a27ff32 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php @@ -75,6 +75,13 @@ class SqlContentEntityStorageSchema implements FieldableEntityStorageSchemaInter protected $database; /** + * The key-value collection for tracking installed storage schema. + * + * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface + */ + protected $installedStorageSchema; + + /** * Constructs a SqlContentEntityStorageSchema. * * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager @@ -95,14 +102,25 @@ public function __construct(EntityManagerInterface $entity_manager, ContentEntit } /** + * @return \Drupal\Core\State\StateInterface + */ + protected function installedStorageSchema() { + if (!isset($this->installedStorageSchema)) { + $this->installedStorageSchema = \Drupal::keyValue('entity.storage_schema.sql'); + } + return $this->installedStorageSchema; + } + + /** * {@inheritdoc} */ public function requiresEntityStorageSchemaChanges(EntityTypeInterface $entity_type, EntityTypeInterface $original) { return $entity_type->getStorageClass() != $original->getStorageClass() || - $entity_type->getKeys() != $original->getKeys() || $entity_type->isRevisionable() != $original->isRevisionable() || - $entity_type->isTranslatable() != $original->isTranslatable(); + $entity_type->isTranslatable() != $original->isTranslatable() || + // Detect changes in key or index definitions. + $this->getEntitySchemaData($entity_type, $this->getEntitySchema($entity_type, TRUE)) != $this->loadEntitySchemaData($original); } /** @@ -140,7 +158,7 @@ public function requiresEntityDataMigration(EntityTypeInterface $entity_type, En // @todo Ask the old storage handler rather than assuming: // https://www.drupal.org/node/2335879. $entity_type->getStorageClass() != $original_storage_class || - !$this->tableIsEmpty($this->storage->getBaseTable()); + !$this->isTableEmpty($this->storage->getBaseTable()); } /** @@ -173,6 +191,9 @@ public function onEntityTypeCreate(EntityTypeInterface $entity_type) { $this->createDedicatedTableSchema($field_storage_definition); } } + + // Save data about entity indexes and keys. + $this->saveEntitySchemaData($entity_type, $schema); } /** @@ -187,8 +208,13 @@ public function onEntityTypeUpdate(EntityTypeInterface $entity_type, EntityTypeI return; } + // TODO + if ($this->requiresEntityDataMigration($entity_type, $original)) { + throw new EntityStorageException(String::format('The SQL storage cannot change the schema for an existing entity type with data.')); + } + // If we have no data just recreate the entity schema from scratch. - if (!$this->requiresEntityDataMigration($entity_type, $original)) { + if ($this->isTableEmpty($this->storage->getBaseTable())) { if ($this->database->supportsTransactionalDDL()) { // If the database supports transactional DDL, we can go ahead and rely // on it. If not, we will have to rollback manually if something fails. @@ -209,9 +235,40 @@ public function onEntityTypeUpdate(EntityTypeInterface $entity_type, EntityTypeI throw $e; } } - // Otherwise, throw an exception. else { - throw new EntityStorageException(String::format('The SQL storage cannot change the schema for an existing entity type with data.')); + $schema_handler = $this->database->schema(); + + // Drop original indexes and unique keys. + foreach ($this->loadEntitySchemaData($entity_type) as $table_name => $schema) { + if (!empty($schema['indexes'])) { + foreach ($schema['indexes'] as $name => $specifier) { + $schema_handler->dropIndex($table_name, $name); + } + } + if (!empty($schema['unique keys'])) { + foreach ($schema['unique keys'] as $name => $specifier) { + $schema_handler->dropUniqueKey($table_name, $name); + } + } + } + + // Create new indexes and unique keys. + $entity_schema = $this->getEntitySchema($entity_type, TRUE); + foreach ($this->getEntitySchemaData($entity_type, $entity_schema) as $table_name => $schema) { + if (!empty($schema['indexes'])) { + foreach ($schema['indexes'] as $name => $specifier) { + $schema_handler->addIndex($table_name, $name, $specifier); + } + } + if (!empty($schema['unique keys'])) { + foreach ($schema['unique keys'] as $name => $specifier) { + $schema_handler->addUniqueKey($table_name, $name, $specifier); + } + } + } + + // Store the updated entity schema. + $this->saveEntitySchemaData($entity_type, $entity_schema); } } @@ -246,6 +303,9 @@ public function onEntityTypeDelete(EntityTypeInterface $entity_type) { $this->originalDefinitions = NULL; $this->storage->setEntityType($actual_definition); + + // Delete the entity schema. + $this->deleteEntitySchemaData($entity_type); } /** @@ -310,37 +370,6 @@ public function finalizePurge(FieldStorageDefinitionInterface $storage_definitio } /** - * Creates revision tables for the specified entity type. - * - * @param \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type - * The entity type definition. - */ - protected function createDedicatedTableRevisionSchema(ContentEntityTypeInterface $entity_type) { - $table_mapping = $this->storage->getTableMapping(); - $schema_manager = $this->database->schema(); - foreach ($this->fieldStorageDefinitions as $definition) { - if ($table_mapping->requiresDedicatedTableStorage($definition)) { - $schema = $this->getDedicatedTableSchema($definition, $entity_type); - $table_name = $table_mapping->getDedicatedRevisionTableName($definition); - $schema_manager->createTable($table_name, $schema[$table_name]); - } - } - } - - /** - * Deletes revision tables for the specified entity type. - */ - protected function dropDedicatedTableRevisionSchema() { - $table_mapping = $this->storage->getTableMapping(); - $schema_manager = $this->database->schema(); - foreach ($this->fieldStorageDefinitions as $definition) { - if ($table_mapping->requiresDedicatedTableStorage($definition)) { - $schema_manager->dropTable($table_mapping->getDedicatedRevisionTableName($definition)); - } - } - } - - /** * Checks that we are dealing with the correct entity type. * * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type @@ -416,7 +445,7 @@ protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $res elseif ($table_mapping->allowsSharedTableStorage($storage_definitions[$field_name])) { $column_names = $table_mapping->getColumnNames($field_name); $storage_definition = $storage_definitions[$field_name]; - $schema[$table_name] = array_merge_recursive($schema[$table_name], $this->getSharedTableFieldSchema($storage_definition, $column_names)); + $schema[$table_name] = array_merge_recursive($schema[$table_name], $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names)); } } @@ -659,6 +688,42 @@ protected function addDefaultLangcodeSchema(&$schema) { } /** + * Loads stored schema data for the given entity type definition. + * + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type definition. + * + * @return array + * The entity schema data array. + */ + protected function loadEntitySchemaData(EntityTypeInterface $entity_type) { + return $this->installedStorageSchema()->get($entity_type->id() . '.schema_data') ?: array(); + } + + /** + * Stores schema data for the given entity type definition. + * + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type definition. + * @param array $schema + * The entity schema data array. + */ + protected function saveEntitySchemaData(EntityTypeInterface $entity_type, $schema) { + $data = $this->getEntitySchemaData($entity_type, $schema); + $this->installedStorageSchema()->set($entity_type->id() . '.schema_data', $data); + } + + /** + * Deletes schema data for the given entity type definition. + * + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type definition. + */ + protected function deleteEntitySchemaData(EntityTypeInterface $entity_type) { + $this->installedStorageSchema()->delete($entity_type->id() . '.schema_data'); + } + + /** * Initializes common information for a base table. * * @param \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type @@ -934,8 +999,7 @@ protected function createSharedTableSchema(FieldStorageDefinitionInterface $stor $created_field_name = $storage_definition->getName(); $table_mapping = $this->storage->getTableMapping(); $column_names = $table_mapping->getColumnNames($created_field_name); - $schema = $this->getSharedTableFieldSchema($storage_definition, $column_names); - $keys = array_diff_key($schema, array('fields' => FALSE)); + $schema_handler = $this->database->schema(); $shared_table_names = array_diff($table_mapping->getTableNames(), $table_mapping->getDedicatedTableNames()); // Iterate over the mapped table to find the ones that will host the created @@ -943,8 +1007,11 @@ protected function createSharedTableSchema(FieldStorageDefinitionInterface $stor foreach ($shared_table_names as $table_name) { foreach ($table_mapping->getFieldNames($table_name) as $field_name) { if ($field_name == $created_field_name) { + // Create field columns. + $schema = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names); + $keys = array_diff_key($schema, array('fields' => FALSE)); foreach ($schema['fields'] as $column_name => $specifier) { - $this->database->schema()->addField($table_name, $column_name, $specifier, $keys); + $schema_handler->addField($table_name, $column_name, $specifier, $keys); } // After creating the field schema skip to the next table. break; @@ -985,7 +1052,6 @@ protected function deleteSharedTableSchema(FieldStorageDefinitionInterface $stor $this->entityManager->getLastInstalledFieldStorageDefinitions($this->entityType->id()) ); $column_names = $table_mapping->getColumnNames($deleted_field_name); - $schema = $this->getSharedTableFieldSchema($storage_definition, $column_names); $schema_handler = $this->database->schema(); $shared_table_names = array_diff($table_mapping->getTableNames(), $table_mapping->getDedicatedTableNames()); @@ -994,6 +1060,8 @@ protected function deleteSharedTableSchema(FieldStorageDefinitionInterface $stor foreach ($shared_table_names as $table_name) { foreach ($table_mapping->getFieldNames($table_name) as $field_name) { if ($field_name == $deleted_field_name) { + $schema = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names); + // Drop indexes and unique keys first. if (!empty($schema['indexes'])) { foreach ($schema['indexes'] as $name => $specifier) { @@ -1146,8 +1214,6 @@ protected function updateSharedTableSchema(FieldStorageDefinitionInterface $stor $updated_field_name = $storage_definition->getName(); $table_mapping = $this->storage->getTableMapping(); $column_names = $table_mapping->getColumnNames($updated_field_name); - $original_schema = $this->getSharedTableFieldSchema($original, $column_names); - $schema = $this->getSharedTableFieldSchema($storage_definition, $column_names); $schema_handler = $this->database->schema(); // Iterate over the mapped table to find the ones that host the deleted @@ -1155,6 +1221,9 @@ protected function updateSharedTableSchema(FieldStorageDefinitionInterface $stor foreach ($table_mapping->getTableNames() as $table_name) { foreach ($table_mapping->getFieldNames($table_name) as $field_name) { if ($field_name == $updated_field_name) { + $original_schema = $this->getSharedTableFieldSchema($original, $table_name, $column_names); + $schema = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names); + // Drop original indexes and unique keys. if (!empty($original_schema['indexes'])) { foreach ($original_schema['indexes'] as $name => $specifier) { @@ -1190,6 +1259,8 @@ protected function updateSharedTableSchema(FieldStorageDefinitionInterface $stor * * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition * The storage definition of the field whose schema has to be returned. + * @param string $table_name + * The name of the table columns will be added to. * @param string[] $column_mapping * A mapping of field column names to database column names. * @@ -1203,7 +1274,7 @@ protected function updateSharedTableSchema(FieldStorageDefinitionInterface $stor * @throws \Drupal\Core\Field\FieldException * Exception thrown if the schema contains reserved column names. */ - protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, array $column_mapping) { + protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) { $schema = array(); $field_schema = $storage_definition->getSchema(); @@ -1252,6 +1323,36 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st return $schema; } + /** + * Adds an index for the specified field to the given schema definition. + * + * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition + * The storage definition of the field for which an index should be added. + * @param array $schema + * A reference to the schema array to be updated. + * @param int $size + * (optional) The index size. Defaults to no limit. + */ + protected function addSharedTableFieldIndex(FieldStorageDefinitionInterface $storage_definition, &$schema, $size = NULL) { + $name = $storage_definition->getName(); + $real_key = $storage_definition->getTargetEntityTypeId() . '__' . $name; + $schema['indexes'][$real_key] = array($size ? array($name, $size) : $name); + } + + /** + * Adds a unique keyfor the specified field to the given schema definition. + * + * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition + * The storage definition of the field for which a unique keyshould be + * added. + * @param array $schema + * A reference to the schema array to be updated. + */ + protected function addSharedTableFieldUniqueKey(FieldStorageDefinitionInterface $storage_definition, &$schema) { + $name = $storage_definition->getName(); + $real_key = $storage_definition->getTargetEntityTypeId() . '__' . $name; + $schema['unique keys'][$real_key] = array($name); + } /** * Returns the SQL schema for a dedicated table. @@ -1459,7 +1560,7 @@ protected function getFieldIndexName(FieldStorageDefinitionInterface $storage_de * @return bool * TRUE if the table is empty, FALSE otherwise. */ - protected function tableIsEmpty($table_name) { + protected function isTableEmpty($table_name) { return !$this->database->schema()->tableExists($table_name) || !$this->database->select($table_name) ->countQuery() diff --git a/core/modules/aggregator/src/FeedStorageSchema.php b/core/modules/aggregator/src/FeedStorageSchema.php index bb197bc..1d5d097 100644 --- a/core/modules/aggregator/src/FeedStorageSchema.php +++ b/core/modules/aggregator/src/FeedStorageSchema.php @@ -7,8 +7,8 @@ namespace Drupal\aggregator; -use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema; +use Drupal\Core\Field\FieldStorageDefinitionInterface; /** * Defines the feed schema handler. @@ -18,22 +18,35 @@ class FeedStorageSchema extends SqlContentEntityStorageSchema { /** * {@inheritdoc} */ - protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) { - $schema = parent::getEntitySchema($entity_type, $reset); - - // Marking the respective fields as NOT NULL makes the indexes more - // performant. - $schema['aggregator_feed']['fields']['url']['not null'] = TRUE; - $schema['aggregator_feed']['fields']['queued']['not null'] = TRUE; - $schema['aggregator_feed']['fields']['title']['not null'] = TRUE; - - $schema['aggregator_feed']['indexes'] += array( - 'aggregator_feed__url' => array(array('url', 255)), - 'aggregator_feed__queued' => array('queued'), - ); - $schema['aggregator_feed']['unique keys'] += array( - 'aggregator_feed__title' => array('title'), - ); + protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) { + $schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping); + $name = $storage_definition->getName(); + + if ($table_name == 'aggregator_feed') { + // Marking the respective fields as NOT NULL makes the indexes more + // performant. + switch ($name) { + case 'url': + case 'queued': + case 'title': + $schema['fields'][$name]['not null'] = TRUE; + break; + } + + switch ($name) { + case 'url': + $this->addSharedTableFieldIndex($storage_definition, $schema, 255); + break; + + case 'queued': + $this->addSharedTableFieldIndex($storage_definition, $schema); + break; + + case 'title': + $this->addSharedTableFieldUniqueKey($storage_definition, $schema); + break; + } + } return $schema; } diff --git a/core/modules/aggregator/src/ItemStorageSchema.php b/core/modules/aggregator/src/ItemStorageSchema.php index ae9af84..b54ebff 100644 --- a/core/modules/aggregator/src/ItemStorageSchema.php +++ b/core/modules/aggregator/src/ItemStorageSchema.php @@ -9,6 +9,7 @@ use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema; +use Drupal\Core\Field\FieldStorageDefinitionInterface; /** * Defines the item schema handler. @@ -21,13 +22,6 @@ class ItemStorageSchema extends SqlContentEntityStorageSchema { protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) { $schema = parent::getEntitySchema($entity_type, $reset); - // Marking the respective fields as NOT NULL makes the indexes more - // performant. - $schema['aggregator_item']['fields']['timestamp']['not null'] = TRUE; - - $schema['aggregator_item']['indexes'] += array( - 'aggregator_item__timestamp' => array('timestamp'), - ); $schema['aggregator_item']['foreign keys'] += array( 'aggregator_item__aggregator_feed' => array( 'table' => 'aggregator_feed', @@ -38,4 +32,29 @@ protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $res return $schema; } + /** + * {@inheritdoc} + */ + protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) { + $schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping); + $name = $storage_definition->getName(); + + if ($table_name == 'aggregator_item') { + // Marking the respective fields as NOT NULL makes the indexes more + // performant. + switch ($name) { + case 'timestamp': + $schema['fields'][$name]['not null'] = TRUE; + break; + } + + switch ($name) { + case 'timestamp': + $this->addSharedTableFieldIndex($storage_definition, $schema); + break; + } + } + + return $schema; + } } diff --git a/core/modules/block_content/src/BlockContentStorageSchema.php b/core/modules/block_content/src/BlockContentStorageSchema.php index 18295d3..cd1ede5 100644 --- a/core/modules/block_content/src/BlockContentStorageSchema.php +++ b/core/modules/block_content/src/BlockContentStorageSchema.php @@ -9,6 +9,7 @@ use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema; +use Drupal\Core\Field\FieldStorageDefinitionInterface; /** * Defines the block content schema handler. @@ -21,10 +22,6 @@ class BlockContentStorageSchema extends SqlContentEntityStorageSchema { protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) { $schema = parent::getEntitySchema($entity_type, $reset); - // Marking the respective fields as NOT NULL makes the indexes more - // performant. - $schema['block_content_field_data']['fields']['info']['not null'] = TRUE; - $schema['block_content_field_data']['unique keys'] += array( 'block_content__info' => array('info', 'langcode'), ); @@ -32,4 +29,24 @@ protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $res return $schema; } + /** + * {@inheritdoc} + */ + protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) { + $schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping); + $name = $storage_definition->getName(); + + if ($table_name == 'block_content_field_data') { + // Marking the respective fields as NOT NULL makes the indexes more + // performant. + switch ($name) { + case 'info': + $schema['fields'][$name]['not null'] = TRUE; + break; + } + } + + return $schema; + } + } diff --git a/core/modules/comment/src/CommentStorageSchema.php b/core/modules/comment/src/CommentStorageSchema.php index 7b9a03c..06755fe 100644 --- a/core/modules/comment/src/CommentStorageSchema.php +++ b/core/modules/comment/src/CommentStorageSchema.php @@ -9,6 +9,7 @@ use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema; +use Drupal\Core\Field\FieldStorageDefinitionInterface; /** * Defines the comment schema handler. @@ -21,13 +22,6 @@ class CommentStorageSchema extends SqlContentEntityStorageSchema { protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) { $schema = parent::getEntitySchema($entity_type, $reset); - // Marking the respective fields as NOT NULL makes the indexes more - // performant. - $schema['comment_field_data']['fields']['created']['not null'] = TRUE; - $schema['comment_field_data']['fields']['thread']['not null'] = TRUE; - - unset($schema['comment_field_data']['indexes']['comment_field__pid__target_id']); - unset($schema['comment_field_data']['indexes']['comment_field__entity_id__target_id']); $schema['comment_field_data']['indexes'] += array( 'comment__status_pid' => array('pid', 'status'), 'comment__num_new' => array( @@ -45,7 +39,6 @@ protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $res 'comment_type', 'default_langcode', ), - 'comment__created' => array('created'), ); $schema['comment_field_data']['foreign keys'] += array( 'comment__author' => array( @@ -57,4 +50,36 @@ protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $res return $schema; } + /** + * {@inheritdoc} + */ + protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) { + $schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping); + $name = $storage_definition->getName(); + + // Remove unneeded indexes. + unset($schema['indexes']['comment_field__pid__target_id']); + unset($schema['indexes']['comment_field__entity_id__target_id']); + + if ($table_name == 'comment_field_data') { + // Marking the respective fields as NOT NULL makes the indexes more + // performant. + switch ($name) { + case 'created': + case 'thread': + $schema['fields'][$name]['not null'] = TRUE; + break; + } + + // Add custom indexes. + switch ($storage_definition->getName()) { + case 'created': + $this->addSharedTableFieldIndex($storage_definition, $schema); + break; + } + } + + return $schema; + } + } diff --git a/core/modules/file/src/FileStorageSchema.php b/core/modules/file/src/FileStorageSchema.php index f223e7b..4d18216 100644 --- a/core/modules/file/src/FileStorageSchema.php +++ b/core/modules/file/src/FileStorageSchema.php @@ -7,8 +7,8 @@ namespace Drupal\file; -use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema; +use Drupal\Core\Field\FieldStorageDefinitionInterface; /** * Defines the file schema handler. @@ -18,24 +18,37 @@ class FileStorageSchema extends SqlContentEntityStorageSchema { /** * {@inheritdoc} */ - protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) { - $schema = parent::getEntitySchema($entity_type, $reset); - - // Marking the respective fields as NOT NULL makes the indexes more - // performant. - $schema['file_managed']['fields']['status']['not null'] = TRUE; - $schema['file_managed']['fields']['changed']['not null'] = TRUE; - $schema['file_managed']['fields']['uri']['not null'] = TRUE; - - // @todo There should be a 'binary' field type or setting. - $schema['file_managed']['fields']['uri']['binary'] = TRUE; - $schema['file_managed']['indexes'] += array( - 'file__status' => array('status'), - 'file__changed' => array('changed'), - ); - $schema['file_managed']['unique keys'] += array( - 'file__uri' => array('uri'), - ); + protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) { + $schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping); + $name = $storage_definition->getName(); + + if ($table_name == 'file_managed') { + // Marking the respective fields as NOT NULL makes the indexes more + // performant. + switch ($name) { + case 'status': + case 'changed': + $schema['fields'][$name]['not null'] = TRUE; + break; + + case 'uri': + $schema['fields'][$name]['not null'] = TRUE; + // @todo There should be a 'binary' field type or setting. + $schema['fields'][$name]['binary'] = TRUE; + break; + } + + switch ($name) { + case 'status': + case 'changed': + $this->addSharedTableFieldIndex($storage_definition, $schema); + break; + + case 'uri': + $this->addSharedTableFieldUniqueKey($storage_definition, $schema); + break; + } + } return $schema; } diff --git a/core/modules/node/src/NodeStorageSchema.php b/core/modules/node/src/NodeStorageSchema.php index 4bd15c0..67d712a 100644 --- a/core/modules/node/src/NodeStorageSchema.php +++ b/core/modules/node/src/NodeStorageSchema.php @@ -9,6 +9,7 @@ use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema; +use Drupal\Core\Field\FieldStorageDefinitionInterface; /** * Defines the node schema handler. @@ -23,19 +24,9 @@ protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $res // Marking the respective fields as NOT NULL makes the indexes more // performant. - $schema['node_field_data']['fields']['changed']['not null'] = TRUE; - $schema['node_field_data']['fields']['created']['not null'] = TRUE; $schema['node_field_data']['fields']['default_langcode']['not null'] = TRUE; - $schema['node_field_data']['fields']['promote']['not null'] = TRUE; - $schema['node_field_data']['fields']['status']['not null'] = TRUE; - $schema['node_field_data']['fields']['sticky']['not null'] = TRUE; - $schema['node_field_data']['fields']['title']['not null'] = TRUE; $schema['node_field_revision']['fields']['default_langcode']['not null'] = TRUE; - // @todo Revisit index definitions in https://drupal.org/node/2015277. - $schema['node_revision']['indexes'] += array( - 'node__langcode' => array('langcode'), - ); $schema['node_revision']['foreign keys'] += array( 'node__revision_author' => array( 'table' => 'users', @@ -44,10 +35,7 @@ protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $res ); $schema['node_field_data']['indexes'] += array( - 'node__changed' => array('changed'), - 'node__created' => array('created'), 'node__default_langcode' => array('default_langcode'), - 'node__langcode' => array('langcode'), 'node__frontpage' => array('promote', 'status', 'sticky', 'created'), 'node__status_type' => array('status', 'type', 'nid'), 'node__title_type' => array('title', array('type', 4)), @@ -61,4 +49,54 @@ protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $res return $schema; } + /** + * {@inheritdoc} + */ + protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) { + $schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping); + $name = $storage_definition->getName(); + + if ($table_name == 'node_revision') { + switch ($name) { + case 'langcode': + $this->addSharedTableFieldIndex($storage_definition, $schema); + break; + } + } + + if ($table_name == 'node_field_data') { + // Marking the respective fields as NOT NULL makes the indexes more + // performant. + switch ($name) { + case 'changed': + case 'created': + case 'promote': + case 'status': + case 'sticky': + case 'title': + $schema['fields'][$name]['not null'] = TRUE; + break; + } + + // @todo Revisit index definitions in https://drupal.org/node/2015277. + switch ($name) { + case 'changed': + case 'created': + case 'langcode': + $this->addSharedTableFieldIndex($storage_definition, $schema); + break; + } + } + + if ($table_name == 'node_field_revision') { + switch ($name) { + case 'langcode': + $this->addSharedTableFieldIndex($storage_definition, $schema); + break; + } + } + + return $schema; + } + } diff --git a/core/modules/system/src/Tests/Entity/EntityDefinitionUpdateTest.php b/core/modules/system/src/Tests/Entity/EntityDefinitionUpdateTest.php index b96dc29..005780d 100644 --- a/core/modules/system/src/Tests/Entity/EntityDefinitionUpdateTest.php +++ b/core/modules/system/src/Tests/Entity/EntityDefinitionUpdateTest.php @@ -96,7 +96,9 @@ public function testEntityTypeUpdateWithData() { $this->state->set('entity_test.entity_test_rev.disable_revisable', TRUE); $this->entityManager->clearCachedDefinitions(); foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) { + $entity_type_id = 'entity_test_rev'; $this->installEntitySchema($entity_type_id); + break; } // Save an entity. diff --git a/core/modules/taxonomy/src/TermStorageSchema.php b/core/modules/taxonomy/src/TermStorageSchema.php index 83e3457..8320020 100644 --- a/core/modules/taxonomy/src/TermStorageSchema.php +++ b/core/modules/taxonomy/src/TermStorageSchema.php @@ -9,6 +9,7 @@ use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema; +use Drupal\Core\Field\FieldStorageDefinitionInterface; /** * Defines the term schema handler. @@ -21,20 +22,10 @@ class TermStorageSchema extends SqlContentEntityStorageSchema { protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) { $schema = parent::getEntitySchema($entity_type, $reset = FALSE); - if (isset($schema['taxonomy_term_field_data'])) { - // Marking the respective fields as NOT NULL makes the indexes more - // performant. - $schema['taxonomy_term_field_data']['fields']['weight']['not null'] = TRUE; - $schema['taxonomy_term_field_data']['fields']['name']['not null'] = TRUE; - - unset($schema['taxonomy_term_field_data']['indexes']['taxonomy_term_field__vid__target_id']); - unset($schema['taxonomy_term_field_data']['indexes']['taxonomy_term_field__description__format']); - $schema['taxonomy_term_field_data']['indexes'] += array( - 'taxonomy_term__tree' => array('vid', 'weight', 'name'), - 'taxonomy_term__vid_name' => array('vid', 'name'), - 'taxonomy_term__name' => array('name'), - ); - } + $schema['taxonomy_term_field_data']['indexes'] += array( + 'taxonomy_term__tree' => array('vid', 'weight', 'name'), + 'taxonomy_term__vid_name' => array('vid', 'name'), + ); $schema['taxonomy_term_hierarchy'] = array( 'description' => 'Stores the hierarchical relationship between terms.', @@ -116,4 +107,35 @@ protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $res return $schema; } + /** + * {@inheritdoc} + */ + protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) { + $schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping); + $name = $storage_definition->getName(); + + // Remove unneeded indexes. + unset($schema['indexes']['taxonomy_term_field__vid__target_id']); + unset($schema['indexes']['taxonomy_term_field__description__format']); + + if ($table_name == 'taxonomy_term_field_data') { + // Marking the respective fields as NOT NULL makes the indexes more + // performant. + switch ($name) { + case 'weight': + case 'name': + $schema['fields'][$name]['not null'] = TRUE; + break; + } + + switch ($name) { + case 'name': + $this->addSharedTableFieldIndex($storage_definition, $schema); + break; + } + } + + return $schema; + } + } diff --git a/core/modules/user/src/UserStorageSchema.php b/core/modules/user/src/UserStorageSchema.php index 0229db2..f021f35 100644 --- a/core/modules/user/src/UserStorageSchema.php +++ b/core/modules/user/src/UserStorageSchema.php @@ -9,6 +9,7 @@ use Drupal\Core\Entity\ContentEntityTypeInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema; +use Drupal\Core\Field\FieldStorageDefinitionInterface; /** * Defines the user schema handler. @@ -21,20 +22,6 @@ class UserStorageSchema extends SqlContentEntityStorageSchema { protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) { $schema = parent::getEntitySchema($entity_type, $reset); - // The "users" table does not use serial identifiers. - $schema['users']['fields']['uid']['type'] = 'int'; - - // Marking the respective fields as NOT NULL makes the indexes more - // performant. - $schema['users_field_data']['fields']['access']['not null'] = TRUE; - $schema['users_field_data']['fields']['created']['not null'] = TRUE; - $schema['users_field_data']['fields']['name']['not null'] = TRUE; - - $schema['users_field_data']['indexes'] += array( - 'user__access' => array('access'), - 'user__created' => array('created'), - 'user__mail' => array('mail'), - ); $schema['users_field_data']['unique keys'] += array( 'user__name' => array('name', 'langcode'), ); @@ -71,4 +58,43 @@ protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $res return $schema; } + /** + * {@inheritdoc} + */ + protected function processIdentifierSchema(&$schema, $key) { + if ($key != $this->entityType->getKey('id')) { + parent::processIdentifierSchema($schema, $key); + } + } + + /** + * {@inheritdoc} + */ + protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) { + $schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping); + $name = $storage_definition->getName(); + + if ($table_name == 'users_field_data') { + // Marking the respective fields as NOT NULL makes the indexes more + // performant. + switch ($name) { + case 'access': + case 'created': + case 'name': + $schema['fields'][$name]['not null'] = TRUE; + break; + } + + switch ($name) { + case 'access': + case 'created': + case 'mail': + $this->addSharedTableFieldIndex($storage_definition, $schema); + break; + } + } + + return $schema; + } + }