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
| Comment | File | Size | Author |
|---|---|---|---|
| #47 | 3061950-47.patch | 6.39 KB | ambot112 |
| #38 | 3061950-37.patch | 7.19 KB | quietone |
| #38 | interdiff-21-37.txt | 1.18 KB | quietone |
| #31 | interdiff-3061950-29-31.txt | 745 bytes | DeFr |
| #31 | 3061950-31.patch | 7.31 KB | DeFr |
Comments
Comment #2
richgerdesThe 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.
Comment #3
richgerdesSetting a more correct component.
Comment #4
amateescu commented@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.phpAnd 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 customfield_default_accessER field is a configurable field (judging by thefield_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 theFieldStorageConfigconfiguration 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...Comment #5
richgerdes@amateescu,
Thanks for taking a look. Its important to note the following:
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_8chrhashprefix, 17 char entity table/revision nametaxonomy_term_r__, 20 character field namefield_default_accessis 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.
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.
Comment #6
mtodor commented@amateescu I have experienced same problem and it is exactly what you have explained. It's different configuration in
FieldStorageConfigandEntityLastInstalledSchemaRepository.Is there some way to fix that in DB? I think that
FieldStorageConfigshould be correct one.@richgerdes I used this code to check it.
You can also output
$field_repositoryand$field_storagein files and diff them.Comment #7
richgerdesSorry 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.
Comment #8
daffie commented@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.
Comment #9
amateescu commented@mtodor:
Yup,
FieldStorageConfigholds 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().Comment #11
amateescu commentedI 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.
Comment #13
hchonovWorked 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.
Comment #15
hchonovActually I am surprised that we need to make so few test adjustments.
Comment #18
daffie commentedPatch looks good. It has enough testing for me. Some minor points left:
Is there for this todo a followup? If not, should we create one?
Nitpick: Could we change the variable
$field_definitionto$das we are not using it anymore.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.Comment #19
anmolgoyal74 commentedAddressed 18.2 and 18.3.
for 18.2
For this case,
$field_definitionis being used in the followup code.Comment #20
anmolgoyal74 commentedFixed CS issue.
Comment #22
daffie commented@anmolgoyal74: Thank you for working on this patch.
$this->entityStoragemust be set before and needs to be updated afterwards.$field_definitioncannot be renamed.After these things are done it is for me RTBC.
Comment #23
spokjeOCD-fueled typo fix in issue title
Comment #24
anmolgoyal74 commentedComment #25
daffie commentedThe 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.
Comment #26
alexpottThe comment in the test about only using the installed definitions and not the live definitions seems to contradict what is commented in the code.
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.
Comment #27
alexpottAh I see where things have got confused... see \Drupal\Core\Entity\EntityFieldManager::getActiveFieldStorageDefinitions()
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.
Comment #29
DeFr commentedStumbled 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".
Comment #31
DeFr commentedPatch updated for the new fail in #29.
Comment #32
andypostany reason to rename variable? looks out of scope
Comment #33
DeFr commentedI'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.
Comment #34
mglamanI 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 namesComment #35
quietone commentedNeeds work for #34
This also needs an issue summary update, the remaining task states that the solution is not yet decided. Is it?
Comment #37
quietone commentedThis 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.
Comment #38
quietone commentedForgot to upload the patch.
Comment #39
quietone commentedSeems that I didn't make the changes to the Issue Summary I intended to. I have do so now.
Comment #40
quietone commentedI 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?
Comment #42
dieuweJust 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.
Comment #43
smustgrave commentedSo what's the decision regarding 26.2
Comment #44
smustgrave commentedMoving back to NW until an answer for #26.2 is added. Or change code.
Comment #46
eric_a commentedEDIT:
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.
Comment #47
ambot112 commentedRecreated the patch from #38 to successfully apply to Drupal 10.3.1.