field_sql_storage_field_storage_write() does a DELETE ... INSERT.
The DELETE is restricted by field language:
<?php
// Delete languages present in the incoming $entity->$field_name.
// Delete all languages if $entity->$field_name is empty.
$languages = !empty($entity->$field_name) ? $field_languages : $all_languages;
?>
This causes a problem in the following situation:
1. Create a new node
2. Add a translation in a new revision.
3. Revert back to the original revision.
The original revision will have values set for $entity->field_name but only in the language of the original revision.
This means that the DELETE query only deletes values from {field_data_FIELD_NAME} WHERE language = the original language.
The result is that the field values for the translations remain in the {field_data_FIELD_NAME} table, albeit within incorrect revision IDs (they point to the middle revision, not the new reverted revision).
Further to this, if you then load the node, because field_sql_storage just loads whatever's in the {field_data_*} table, it will happily load those field values back into the $node object - since they're there in the table ready to be loaded.
Major for two reasons:
1. if you had open translation permissions and someone added something to a translation which was the cause of the revert, the revert will fail. The only way to remove that content would be direct database queries or manually deleting then recreating the entire node, or saving a new revision with different translated values instead of reverting. Additionally if you do something like revert then edit, the edit operation will completely resurrect the translations including with the correct revision ID (I think).
2. The bug leaves the database in an inconsistent state - the field_data_* tables are supposed to store data for the current revision, not the current revision and any random multilingual data from previous revisions.
I'm uploading a patch but I don't think it's committable - this just removes the language check altogether. This removes support for saving an entity with only translations in some languages populated - since anything else will be deleted but not re-inserted.
This is similar-ish to #1126000: hook_field_*() called on fields not set in the $entity object (partial updates) in the sense that partial entity updates are broken.
Attachment | Size | Status | Test result | Operations |
---|---|---|---|---|
field_sql_storage_revisions.patch | 2.1 KB | Ignored: Check issue status. | None | None |