Problem/Motivation

During an upgrade from 8.6.16 to 8.7.3, I ran into an issue with taxonomy_post_update_make_taxonomy_term_revisionable() .

The following error is thrown during processing of the update.

Base table or view not found: 1146 Table 'drupal.tmp_ed8154taxonomy_term_r__ff793441e7' doesn't exist: ...

.

Through some debugging, I determined that the temporary table, tmp_ed8154taxonomy_term_r__ff793441e7 was related to a custom field, field_default_access, an entity reference field on my Vocabulary. The default tempary table name, tmp__taxonomy_term_revision__field_default_access, turns out to be 49 characters, and is replaced with the hash format tmp table name, see DefaultTableMapping::generateFieldTableName() . While tracing the code for the EntityDefinitionUpdateManager::updateFieldableEntityType() , I discovered that this table was actually being created, but with a different sha255 has, resulting in the table name tmp_ed8154taxonomy_term_r__d348111e42.

Further discovery determined that SQLContentEntityStorage::saveToDedicatedTables() doesn't use the "$field_storage_definitions" used through out the update code, but calls $field_definition->getFieldStorageDefinition(); , which results in a different instance of the storage definition, with a different ( getUniqueStorageIdentifier() ), and as a result the table name isn't mapped correctly.

The issue here may be related to #3056539: Updating an entity type from non-revisionable to revisionable fails if it has non-revisionable fields stored in dedicated tables, however it doesn't appear the missing table in that issue is the result of the incorrect hashed table id, but it may be the result of not using the current table mapping correctly.

Proposed resolution

Changes the entity storage to use its internal definitions instead of the ones provided by the entity field manager.

Remaining tasks

#26.2
Review
Commit

User interface changes

None

API changes

None

Data model changes

None

Release notes snippet

Comments

richgerdes created an issue. See original summary.

richgerdes’s picture

Issue summary: View changes
Status: Active » Needs review
StatusFileSize
new808 bytes

The attached patch is a rough attempt at getting this working in a simple way. It simply updates the variable if there is a valid config to replace it with.

I don't have time to write tests for this patch at the moment, but all that should be required is calling $storage->restore($entity) after calling $storage->setFieldStorageDefinitions($field_storage_definitions); , and then verifying that the correct table was queried.

Please let me know if more information is needed.

richgerdes’s picture

Component: taxonomy.module » entity system

Setting a more correct component.

amateescu’s picture

Status: Needs review » Postponed (maintainer needs more info)

@richgerdes, I just tested the following steps manually:

- installed Drupal 8.6.0
- created a test ER field on the Tags vocabulary (configured to reference nodes)
- created a test node and then a test test term with a reference to the node
- updated the codebase to 8.8.x, then ran updates through update.php

And everything worked without errors, so the issue you encountered is not the expected behavior of the new EntityDefinitionUpdateManager::updateFieldableEntityType() API.

If you have a backup database, can you try to debug the update process again and see how or why you were getting different values from FieldStorageConfig::getUniqueStorageIdentifier()? I'm assuming that the custom field_default_access ER field is a configurable field (judging by the field_ prefix), so the only possible explanation is that the two field storage definitions, the one stored in the last installed schema repository is different than the one stored in the FieldStorageConfig configuration entity. Which make me think this is a case of "corrupted database" (specifically, the last installed schema repository), and it's not something that can be fixed in core...

richgerdes’s picture

Status: Postponed (maintainer needs more info) » Needs review

@amateescu,

Thanks for taking a look. Its important to note the following:

The default tempary table name, tmp<HASH>__taxonomy_term_revision__field_default_access, turns out to be 49 characters

The bug is the result of the temporary table mapping. In the cause above, this issue was the result of the the field length. The code hashes the field name (based on uuid) if the table is longer the 48 characters. In this case the table name (12 character tmp_8chrhash prefix, 17 char entity table/revision name taxonomy_term_r__, 20 character field name field_default_access is 49 characters, which it above the 48 character limit, and is hashed. This above issue presents it self as the result of the DefaultTableMapping::generateFieldTableName.

I was able to test htis with a backup of my site from 8.6.16. The issue is still present when moving to drupal/core:8.8.x-dev. See the error below.

Drupal\Core\Database\DatabaseExceptionWrapper: SQLSTATE[42S02]: Base table or view not found: 1146 Table
'drupal3061950.tmp_36cfa7taxonomy_term_r__ff793441e7' doesn't exist: INSERT INTO {tmp_36cfa7taxonomy_term_r__ff793441e7}....

This issue shouldn't be related to use an entity reference field (i was using one), as any long ~20 character field name should result in the issue. This also should be recreate-able with nodes, if you use a 32+ character field name (say field_this_is_a_long_field_name), but inherently presented is self as the result of adding the field to taxonomy terms.

I'm not sure if "entity system" is the correct component, please reassign it if there is a more correct one.

mtodor’s picture

@amateescu I have experienced same problem and it is exactly what you have explained. It's different configuration in FieldStorageConfig and EntityLastInstalledSchemaRepository.

Is there some way to fix that in DB? I think that FieldStorageConfig should be correct one.

@richgerdes I used this code to check it.

use Drupal\field\Entity\FieldStorageConfig;

/** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepository $last_installed_schema_repository */
$last_installed_schema_repository = Drupal::service('entity.last_installed_schema.repository');

/** @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] $from_sr */
$from_repository = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions('taxonomy_term');

$field_name = '_YOUR_FIELD_NAME_HERE_';

$field_repository = $from_repository[$field_name];
echo 'From repository: ' . $field_repository->getUniqueStorageIdentifier() . PHP_EOL;

$field_storage = FieldStorageConfig::load('taxonomy_term.' . $field_name);
echo 'From storage: ' . $field_storage->getUniqueStorageIdentifier() . PHP_EOL;

You can also output $field_repository and $field_storage in files and diff them.

richgerdes’s picture

Sorry if I was unclear, yes, I confirmed that the data was incorrect before I opened the issue. I didn't fully understand what was going wrong, but that's what it appeared to be. For all our sanity, below is the output of the script @mtodor provided.

$ drush php-script ./scripts/3061950.php
From repository: 759ad6c3-d957-4720-9469-f996b713839c
From storage: e15701ee-8cfd-4d8e-bbee-614df15c0534
daffie’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

@richgerdes: Could you make a test that mimics the situation and that results in the given exception. And with your fix does not result in the exception. Like changing a non-revisionable entity type with some entity instances and changing it to a revisionable entity type.

amateescu’s picture

@mtodor:

Is there some way to fix that in DB? I think that FieldStorageConfig should be correct one.

Yup, FieldStorageConfig holds the correct (current) values, and I think the only quick fix is to set it as the last installed definition directly by calling \Drupal\Core\Entity\EntityLastInstalledSchemaRepository::setLastInstalledFieldStorageDefinition().

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.9 was released on November 6 and is the final full bugfix release for the Drupal 8.7.x series. Drupal 8.7.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.8.0 on December 4, 2019. (Drupal 8.8.0-beta1 is available for testing.)

Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

amateescu’s picture

Status: Needs work » Needs review
Issue tags: +WI critical
StatusFileSize
new1.9 KB

I opened #3101598: Differring field storage identifiers should be reported as a missing field storage definition update for helping/guiding sites that might be in the same situation as the one reported by @richgerdes here, but I think the current issue title and scope also describe a valid bug: since the entity storage was changed to rely on the last installed definitions in #2554235: Make the content entity storage and entity query use the last installed definitions instead of the ones living in code, the two places where we generate table names based on the live (in-code) definitions could very much be a source of trouble.

Here's a start for a patch which changes the entity storage to use its internal definitions instead of the ones provided by the entity field manager.

Status: Needs review » Needs work

The last submitted patch, 11: 3061950-11.patch, failed testing. View results

hchonov’s picture

Version: 8.8.x-dev » 8.9.x-dev
Status: Needs work » Needs review
StatusFileSize
new6.02 KB

Worked independently on the same problem in #3113306: Last installed field storage definitions not used when loading from / saving to dedicated tables, which looks like a duplicate. That means that issues for the same problem are being opened and we should better solve this faster.

Here is a similar patch that should be passing all tests.

I don't think that we need explicit test coverage beside the one that I had to adjust in \Drupal\KernelTests\Core\Field\FieldMissingTypeTest, which is implicitly asserting that the active field storage definitions are being used instead of the live ones.

A next task would be to keep track of the installed field definitions the same way as we keep track of the installed field storage definitions. I've left todos in the code for that, but this should be pursued in a follow-up issue.

Status: Needs review » Needs work

The last submitted patch, 13: 3061950-13.patch, failed testing. View results

hchonov’s picture

Status: Needs work » Needs review
StatusFileSize
new6.97 KB
new1.88 KB

Actually I am surprised that we need to make so few test adjustments.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

daffie’s picture

Status: Needs review » Needs work
Issue tags: -Needs tests

Patch looks good. It has enough testing for me. Some minor points left:

  1. +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
    @@ -1235,9 +1235,14 @@ protected function loadFromDedicatedTables(array &$values, $load_from_revision)
    +      // @todo add support for last installed field definitions.
    
    @@ -1323,13 +1328,18 @@ protected function saveToDedicatedTables(ContentEntityInterface $entity, $update
    +    // @todo add support for last installed field definitions.
    

    Is there for this todo a followup? If not, should we create one?

  2. +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
    @@ -1235,9 +1235,14 @@ protected function loadFromDedicatedTables(array &$values, $load_from_revision)
           foreach ($definitions[$bundle] as $field_name => $field_definition) {
    
    @@ -1323,13 +1328,18 @@ protected function saveToDedicatedTables(ContentEntityInterface $entity, $update
         foreach ($definitions as $field_name => $field_definition) {
    

    Nitpick: Could we change the variable $field_definition to $d as we are not using it anymore.

  3. +++ b/core/modules/jsonapi/tests/src/Functional/ResourceTestBase.php
    @@ -343,6 +343,14 @@ protected function setUpFields(EntityInterface $entity, UserInterface $account)
    +    // Ensure that a new instance of the entity storage is created, so that it
    +    // contains the new field storage definitions as part of the active field
    +    // storage definitions.
    +    /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
    +    $entity_type_manager = $this->container->get('entity_type.manager');
    +    $entity_type_manager->clearCachedDefinitions();
    +    $this->entityStorage = $entity_type_manager->getStorage(static::$entityTypeId);
    

    Can we move this piece of code to the method setup() as we are there setting the value of $this->entityStorage. It becomes a bit confusing/double now.

anmolgoyal74’s picture

Status: Needs work » Needs review
StatusFileSize
new7.43 KB
new5.6 KB

Addressed 18.2 and 18.3.

for 18.2

@@ -1323,13 +1328,18 @@ protected function saveToDedicatedTables(ContentEntityInterface $entity, $update
     foreach ($definitions as $field_name => $field_definition) {

For this case,$field_definition is being used in the followup code.

anmolgoyal74’s picture

StatusFileSize
new7.43 KB
new700 bytes

Fixed CS issue.

Status: Needs review » Needs work

The last submitted patch, 20: 3061950-20.patch, failed testing. View results

daffie’s picture

@anmolgoyal74: Thank you for working on this patch.

  1. The change I asked for in #18.3 needs to be reverted. The value of $this->entityStorage must be set before and needs to be updated afterwards.
  2. You are right that the second instance of the variable $field_definition cannot be renamed.
  3. For the todo's: Just leave them. I have looked in the ussue queue if there is an issue for the todo's, but I cannot find it.

After these things are done it is for me RTBC.

spokje’s picture

Title: SQLContentEntityStorage::saveToDedicatedTables() doesn't correctly use storage configuraiton » SQLContentEntityStorage::saveToDedicatedTables() doesn't correctly use storage configuration

OCD-fueled typo fix in issue title

anmolgoyal74’s picture

Status: Needs work » Needs review
StatusFileSize
new7.04 KB
new1.83 KB
daffie’s picture

Status: Needs review » Reviewed & tested by the community

The patch implements the proposed solution from the IS.
All changes in the patch look good to me.
Some tests needed to be changed for the solution.
There is no API change, therefore no CR needed.
I could not find any outstanding issues for the added @todo's.
For me the patch is RTBC.

@anmolgoyal74: My apologies for making you do the by my requested changes and then having you reverting them.

alexpott’s picture

  1. +++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
    @@ -1196,9 +1196,14 @@ protected function loadFromDedicatedTables(array &$values, $load_from_revision)
    +      // @todo add support for last installed field definitions.
    ...
    +        // Consider only the active field storage definitions.
    +        if (!isset($this->fieldStorageDefinitions[$field_name])) {
    
    @@ -1284,13 +1289,18 @@ protected function saveToDedicatedTables(ContentEntityInterface $entity, $update
    +    // @todo add support for last installed field definitions.
    ...
    +      // Consider only the active field storage definitions.
    +      if (!isset($this->fieldStorageDefinitions[$field_name])) {
    +        continue;
    +      }
    
    +++ b/core/tests/Drupal/KernelTests/Core/Field/FieldMissingTypeTest.php
    @@ -56,13 +56,15 @@ protected function setUp(): void {
    +   * As the storage is using the installed instead the live field storage
    +   * definitions the manipulated field storage entity should not be loaded and
    +   * therefore the exception should not be thrown.
    

    The comment in the test about only using the installed definitions and not the live definitions seems to contradict what is commented in the code.

  2. +++ b/core/modules/jsonapi/tests/src/Functional/ResourceTestBase.php
    @@ -343,6 +343,14 @@ protected function setUpFields(EntityInterface $entity, UserInterface $account)
    +    // Ensure that a new instance of the entity storage is created, so that it
    +    // contains the new field storage definitions as part of the active field
    +    // storage definitions.
    +    /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
    +    $entity_type_manager = $this->container->get('entity_type.manager');
    +    $entity_type_manager->clearCachedDefinitions();
    +    $this->entityStorage = $entity_type_manager->getStorage(static::$entityTypeId);
    

    This test class should not be adding services like entityStorage to the test. It's a recipe for unexpected side effects. That said this change is a concern for unintended impacts on contrib and custom tests.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

Ah I see where things have got confused... see \Drupal\Core\Entity\EntityFieldManager::getActiveFieldStorageDefinitions()

  public function getActiveFieldStorageDefinitions($entity_type_id) {
    if (!isset($this->activeFieldStorageDefinitions[$entity_type_id])) {
      $this->activeFieldStorageDefinitions[$entity_type_id] = $this->entityLastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions($entity_type_id);
    }
    return $this->activeFieldStorageDefinitions[$entity_type_id] ?: $this->getFieldStorageDefinitions($entity_type_id);
  }

getActiveFieldStorageDefinitions() doesn't do what you think it does... the change we're making here is changing things to only use last installed definitions! So that makes the comments incorrect.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

DeFr’s picture

StatusFileSize
new6.58 KB
new1.73 KB

Stumbled on this issue while trying to update a BaseField cardinality from single to unlimited in an updateFieldableEntityType call ; loadFromDedicatedTable reading the current base field instead of the last installed one leads to issues in that case. I can confirm the patch fixes that case.

Attaching a re-rolled patch (patch applied with fuzz), with comments fix for 26.1. That being said, I wonder if simply removing the @todo and keeping the active in the comment might be better, given that those fields are retrieved with getActiveFieldStorageDefinitions.

Not sure of what to do for 26.2 ; what's happenning here is that ResourceTestBase already got entityStorage injected. After the new fields creation, that storage initially injected is outdated, because it doesn't contain those new fields definitions ; that's why this patch reloads a fresh storage in $this->entityStorage. Not storing it at all on the object and fetching a fresh entityStorage when needed would solve that issue, but that seems like a far more invasive change to the tests, compared to "If your test is adding new fields, you-ll need to fetch a fresh entity storage".

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

DeFr’s picture

Status: Needs work » Needs review
StatusFileSize
new7.31 KB
new745 bytes

Patch updated for the new fail in #29.

andypost’s picture

+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php
@@ -1205,8 +1205,12 @@ protected function loadFromDedicatedTables(array &$values, $load_from_revision)
-      foreach ($definitions[$bundle] as $field_name => $field_definition) {
-        $storage_definition = $field_definition->getFieldStorageDefinition();
+      foreach ($definitions[$bundle] as $field_name => $d) {
...
+        $storage_definition = $this->fieldStorageDefinitions[$field_name];

any reason to rename variable? looks out of scope

DeFr’s picture

I'm not the one who introduced that change so I can't tell for sure, but I guess that as $field_definition is now longer used, the variable name was changed to match the style of the outer foreach loop (first line of the context of the patch, foreach ($bundles as $bundle => $v) { ), so it's more consistent with the style of the surrounding code.

That being said, I can change that back to the original variable name if needed.

mglaman’s picture

I think it'd be better to do foreach (array_keys($definitions[$bundle] then instead of having a dead variable. That way we only iterate over the field names

quietone’s picture

Status: Needs review » Needs work
Issue tags: +Bug Smash Initiative, +Needs issue summary update

Needs work for #34

This also needs an issue summary update, the remaining task states that the solution is not yet decided. Is it?

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

quietone’s picture

Issue summary: View changes
Issue tags: -Needs issue summary update

This patch restores the changes to the comments, which is what I understand #27 to mean. I also reverted the change to the foreach to keep this in scope.

The change made to ManageFieldFunctionalTest in #31 is unexpected. If the functional test is testing what a user would do through the UI, then clearing the cache in the middle of working is not an expected action. Am I wrong and this is the correct fix or should that be at the beginning of the test or is there something still to work on in the patch?

I have updated the proposed resolution and remaining tasks in the IS, removing tag.

quietone’s picture

Status: Needs work » Needs review
StatusFileSize
new1.18 KB
new7.19 KB

Forgot to upload the patch.

quietone’s picture

Issue summary: View changes

Seems that I didn't make the changes to the Issue Summary I intended to. I have do so now.

quietone’s picture

Issue summary: View changes

I put this issue in #bugsmash and lendude replied is agreement with #37, middle paragraph, that the change of storage in the middle of a functional test doesn't seem right. And that relates back to #26.2 and the reply in #29, third paragraph. So what is the direction this should take?

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

dieuwe’s picture

Just chiming in to say that the patch from #38 works perfectly to solve my issues - I added a custom number field with unlimited cardinality to an existing entity via an update hook + base field info alter hook, which was previously causing the "table not found" error to be thrown on the entity's forms. Now the field loads and values can be properly stored. I know that's not the same as what the issue description is for, but searching through various related issues brought me here.

smustgrave’s picture

So what's the decision regarding 26.2

smustgrave’s picture

Status: Needs review » Needs work

Moving back to NW until an answer for #26.2 is added. Or change code.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

eric_a’s picture

Issue tags: +Needs reroll

EDIT:
Patch #15 applies to 10.2.7. It does not apply to 10.3.0.

Patch from #38 doesn't apply to Drupal 10.3.0.
Something must have changed in FieldMissingTypeTest.

patching file core/tests/Drupal/KernelTests/Core/Field/FieldMissingTypeTest.php
Hunk #1 FAILED at 56.

ambot112’s picture

StatusFileSize
new6.39 KB

Recreated the patch from #38 to successfully apply to Drupal 10.3.1.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.