diff --git a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php index 26140a6..8accff2 100644 --- a/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php @@ -1022,6 +1022,7 @@ protected function processRevisionDataTable(ContentEntityTypeInterface $entity_t protected function processIdentifierSchema(&$schema, $key) { if ($schema['fields'][$key]['type'] == 'int') { $schema['fields'][$key]['type'] = 'serial'; + $schema['fields'][$key]['not null'] = TRUE; } unset($schema['fields'][$key]['default']); } @@ -1390,6 +1391,7 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st $field_name = $storage_definition->getName(); $field_description = $storage_definition->getDescription(); + $base_table = $this->storage->getBaseTable(); foreach ($column_mapping as $field_column_name => $schema_field_name) { $column_schema = $field_schema['columns'][$field_column_name]; @@ -1400,13 +1402,16 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st $keys = $this->entityType->getKeys() + array('langcode' => 'langcode'); // The label is an entity key, but label fields are not necessarily // required. + unset($keys['label']); // Because entity ID and revision ID are both serial fields in the base // and revision table respectively, the revision ID is not known yet, when // inserting data into the base table. Instead the revision ID in the base // table is updated after the data has been inserted into the revision // table. For this reason the revision ID field cannot be marked as NOT // NULL. - unset($keys['label'], $keys['revision']); + if ($table_name == $base_table) { + unset($keys['revision']); + } // In order to optimize indexes, forbid NULL values in Key fields. Other // columns necessarily allow NULL values in order to support adding a // base field definition to an entity type with non-empty base tables. @@ -1614,9 +1619,7 @@ protected function getDedicatedTableSchema(FieldStorageDefinitionInterface $stor // Properties marked as 'required' do not allow NULL values, others do. // Note: this works because dedicated tables contain no row for empty // fields. - if (isset($properties[$column_name])) { - $data_schema['fields'][$real_name]['not null'] = $properties[$column_name]->isRequired(); - } + $data_schema['fields'][$real_name]['not null'] = $properties[$column_name]->isRequired(); } // Add indexes. diff --git a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php index a3a7013..74a1d43 100644 --- a/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php +++ b/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php @@ -10,6 +10,7 @@ use Drupal\Core\Entity\ContentEntityType; use Drupal\Core\Entity\Sql\DefaultTableMapping; use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema; +use Drupal\Core\TypedData\DataDefinition; use Drupal\Tests\UnitTestCase; /** @@ -257,72 +258,89 @@ public function testGetSchemaBase() { 'description' => 'The name field.', 'type' => 'varchar', 'length' => 255, + 'not null' => FALSE, ), 'description__value' => array( 'description' => 'The description field.', 'type' => 'text', + 'not null' => FALSE, ), 'description__format' => array( 'description' => 'The description field.', 'type' => 'varchar', + 'not null' => FALSE, ), 'uuid' => array( 'description' => 'The uuid field.', 'type' => 'varchar', 'length' => 128, + 'not null' => FALSE, ), 'hash' => array( 'description' => 'The hash field.', 'type' => 'varchar', 'length' => 20, + 'not null' => FALSE, ), 'email__username' => array( 'description' => 'The email field.', 'type' => 'varchar', + 'not null' => FALSE, ), 'email__hostname' => array( 'description' => 'The email field.', 'type' => 'varchar', + 'not null' => FALSE, ), 'email__domain' => array( 'description' => 'The email field.', 'type' => 'varchar', + 'not null' => FALSE, ), 'owner' => array( 'description' => 'The owner field.', 'type' => 'int', + 'not null' => FALSE, ), 'translator' => array( 'description' => 'The translator field.', 'type' => 'int', + 'not null' => FALSE, ), 'location__country' => array( 'description' => 'The location field.', 'type' => 'varchar', + 'not null' => FALSE, ), 'location__state' => array( 'description' => 'The location field.', 'type' => 'varchar', + 'not null' => FALSE, ), 'location__city' => array( 'description' => 'The location field.', 'type' => 'varchar', + 'not null' => FALSE, ), 'editor' => array( 'description' => 'The editor field.', 'type' => 'int', + 'not null' => FALSE, ), 'editor_revision__target_id' => array( 'description' => 'The editor_revision field.', 'type' => 'int', + 'not null' => FALSE, ), 'editor_revision__target_revision_id' => array( 'description' => 'The editor_revision field.', 'type' => 'int', + 'not null' => FALSE, ), 'long_index_name' => array( 'description' => 'The long_index_name field.', 'type' => 'int', + 'not null' => FALSE, ), 'default_langcode' => array( 'description' => 'Boolean indicating whether field values are in the default entity language.', @@ -430,6 +448,7 @@ public function testGetSchemaRevisionable() { 'revision_id' => array( 'description' => 'The revision_id field.', 'type' => 'int', + 'not null' => FALSE, ) ), 'primary key' => array('id'), @@ -455,6 +474,7 @@ public function testGetSchemaRevisionable() { 'revision_id' => array( 'description' => 'The revision_id field.', 'type' => 'serial', + 'not null' => TRUE, ), ), 'primary key' => array('revision_id'), @@ -632,6 +652,7 @@ public function testGetSchemaRevisionableTranslatable() { 'revision_id' => array( 'description' => 'The revision_id field.', 'type' => 'int', + 'not null' => FALSE, ), 'langcode' => array( 'description' => 'The langcode field.', @@ -662,6 +683,7 @@ public function testGetSchemaRevisionableTranslatable() { 'revision_id' => array( 'description' => 'The revision_id field.', 'type' => 'serial', + 'not null' => TRUE, ), 'langcode' => array( 'description' => 'The langcode field.', @@ -692,6 +714,7 @@ public function testGetSchemaRevisionableTranslatable() { 'revision_id' => array( 'description' => 'The revision_id field.', 'type' => 'int', + 'not null' => TRUE, ), 'langcode' => array( 'description' => 'The langcode field.', @@ -722,6 +745,7 @@ public function testGetSchemaRevisionableTranslatable() { 'revision_id' => array( 'description' => 'The revision_id field.', 'type' => 'int', + 'not null' => TRUE, ), 'langcode' => array( 'description' => 'The langcode field.', @@ -1229,6 +1253,19 @@ public function setUpStorageDefinition($field_name, array $schema) { $this->storageDefinitions[$field_name]->expects($this->any()) ->method('getColumns') ->will($this->returnValue($schema['columns'])); + // Add property definitions. + if (!empty($schema['columns'])) { + $property_definitions = array(); + foreach ($schema['columns'] as $column => $info) { + $property_definitions[$column] = $this->getMock('Drupal\Core\TypedData\DataDefinitionInterface'); + $property_definitions[$column]->expects($this->any()) + ->method('isRequired') + ->will($this->returnValue(!empty($info['not null']))); + } + $this->storageDefinitions[$field_name]->expects($this->any()) + ->method('getPropertyDefinitions') + ->will($this->returnValue($property_definitions)); + } } }