Problem/Motivation

Entity Queries with a condition on the revision field will lead to the wrong results when searching through all revisions, as the revision field defined in ContentEntityBase::baseFieldDefinitions() is not flagged as revisionable and therefore Drupal\Core\Entity\Query\Sql\Tables::addField() will create the query for the revision field for the data table instead for the data revision table.

As an example the following entity query
\Drupal::entityQuery("node")->condition("vid", 2)->allRevisions()->execute();
results in the following SQL:

SELECT base_table.vid AS vid, base_table.nid AS nid
FROM node_revision base_table
INNER JOIN node_field_data node_field_data ON node_field_data.nid = base_table.nid
WHERE  (node_field_data.vid = '2');

Proposed resolution

Fix Drupal\Core\Entity\Query\Sql\Tables::addField() and ensure that the revision ID field is taken from the revision tables if all revisions are being queried.

Remaining tasks

Review.

User interface changes

Nope.

API changes

Nope.

Data model changes

Nope.

Comments

hchonov created an issue. See original summary.

Status: Needs review » Needs work

The last submitted patch, entity_query_revision_condition_failing_test.patch, failed testing.

hchonov’s picture

Status: Needs work » Needs review
StatusFileSize
new3.68 KB

This is at least how I think the patch should look like, but there will be exceptions a lot of exceptions now. At least locally I get the following message during the tests :

Drupal\KernelTests\Core\Entity\EntityQueryTest::testEntityQuery Array to string conversion /Users/hchonov/workspace/devd8/drupal/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php:219 /Users/hchonov/workspace/devd8/drupal/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php:107 /Users/hchonov/workspace/devd8/drupal/core/lib/Drupal/Core/Database/Schema.php:596 /Users/hchonov/workspace/devd8/drupal/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php:267 /Users/hchonov/workspace/devd8/drupal/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php:1356 /Users/hchonov/workspace/devd8/drupal/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php:1452 /Users/hchonov/workspace/devd8/drupal/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php:1357 /Users/hchonov/workspace/devd8/drupal/core/lib/Drupal/Core/Entity/EntityTypeListener.php:71 /Users/hchonov/workspace/devd8/drupal/core/lib/Drupal/Core/Entity/EntityManager.php:384 /Users/hchonov/workspace/devd8/drupal/core/tests/Drupal/KernelTests/KernelTestBase.php:832 /Users/hchonov/workspace/devd8/drupal/core/tests/Drupal/KernelTests/Core/Entity/EntityQueryTest.php:63

Status: Needs review » Needs work

The last submitted patch, 3: 2766135-3.patch, failed testing.

hchonov’s picture

Status: Needs work » Needs review
StatusFileSize
new7.24 KB
new3.92 KB

The previous problems and exceptions were caused by SqlContentEntityStorage::getTableMapping where after making the revision field revisionable it being added twice to the table mapping and later SqlContentEntityStorageSchema::getEntitySchema will break the settings of the field when it occurs twice, because we use there array_merge_recursive. I've added a check that the revision field is revisionable and now it will not be added twice to the table mapping.
I've also removed the revision fields definitions from the test entities as it should be provided now from ContentEntityBase::baseFieldDefinitions.

hchonov’s picture

StatusFileSize
new7.3 KB
new621 bytes

I've deleted a whitespace only.

hchonov’s picture

Issue summary: View changes

I think that if this gets in, there might be custom/contrib module entities which define the revision field itself and do not retrieve it from ContentEntityBase::baseFieldDefinitions. Would be a Change Record sufficient for this change to inform the others about the change? Are we targeting 8.2.x or 8.1.x?

The last submitted patch, 5: 2766135-5.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 6: 2766135-6.patch, failed testing.

hchonov’s picture

Status: Needs work » Needs review
StatusFileSize
new8.65 KB
new1.26 KB

So so and now I've added the update.

Status: Needs review » Needs work

The last submitted patch, 10: 2766135-10.patch, failed testing.

jeroen.b’s picture

Priority: Normal » Major
Status: Needs work » Needs review
StatusFileSize
new912 bytes

I think this is quite a big bug. This also did work before (Drupal 8.0.3).
I attached the patch that I'm currently using to solve this. (I also set ->setRevisionable(TRUE) in baseFieldDefinitions on the revision field on custom entities).

Status: Needs review » Needs work

The last submitted patch, 12: 2766135-12.patch, failed testing.

jeroen.b’s picture

Status: Needs work » Needs review
StatusFileSize
new932 bytes

This should apply. Note that the patch is not complete and only works for custom entities, only use it if you need a quick fix.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

timmillwood’s picture

Status: Needs review » Needs work

I know it makes sense for the 'revision' field to be revisionable, but does it *need* to be?
Could we not just add some conditions into the query to make sure it queries the right table?

hchonov’s picture

@timmillwood in this case you have to ask for the revision key and then do specific stuff only for it ... I prefer a general solution and the general solution is that the revision field is revisionable...

hchonov’s picture

@jeroen.b what you've posted here is already included in my patch.

andypost’s picture

jeroen.b’s picture

@hchonov I know. Your patch is more complete. My patch should not be committed to core.
My patch is only for people who need a quick fix for custom entities who don't want to use your patch yet as it might not work correctly as it does some other stuff to existing entities too.

@timmillwood, why shouldn't it be marked "revisionable"? I think that's actually what that property is supposed to be used for.

jmuzz’s picture

We should try to follow best practices as much as possible. It looks to me like the property should be marked revisionable. It's probably the more likely solution to get committed to core.

Still needs work as the full patch hasn't passed tests yet.

jmuzz’s picture

@hchonov Why does the patch make a change to $fields['langcode'] ? If it isn't needed to solve the problem in the summary it could be moved to a separate issue to simplify this one.

alexpott’s picture

Issue tags: +Needs tests

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

chipway’s picture

StatusFileSize
new7.77 KB
new1.05 KB

Patch didn't apply. Rerolled after solving conflict on system.install.

hass’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 25: 2766135-25.patch, failed testing.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

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

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

hchonov’s picture

Issue tags: +Entity query
trevorbradley’s picture

I just hit this myself, trying to pull paragraphs data, which heavily rely on older revisions (particularly when they're cloned).

Just a quick request - is there actually an alternate to QueryInterface's condition method that would actually filter on $revision_id? A replacement for:

$query->allRevisions()->condition('type','my_paragraph_type')->condition('id',12345)->condition('revision_id',12346);

That properly works for filtering on non-current revision_ids?

As previously discussed here, this is generating the query:

SELECT base_table.revision_id AS revision_id, base_table.id AS id FROM paragraphs_item_revision base_table INNER JOIN paragraphs_item_field_data paragraphs_item_field_data ON paragraphs_item_field_data.id = base_table.id WHERE (paragraphs_item_field_data.type = 'my_paragraph_type') AND (paragraphs_item_field_data.id = '12345') AND (paragraphs_item_field_data.revision_id = '12346');

Except paragraphs_item_field_data only contains the most recent revision_id. If I could query against the paragraphs_item_revision table instead, the query works, but condition doesn't take table names.

My quick hack is to not filter on revision_id at all, but rather to use $query->allRevisions()->condition('type','my_paragraph_type')->condition('id',12345);, gathering ALL the $revision_ids as [ $revision_id => $id] pairs, then filter on the data manually after the query is complete. Very hacky, and it may scale very poorly but it does work.

I was wondering if there was something else temporary, but more elegant, that didn't involve dumping entityQuery outright.

nwoodland’s picture

My org has encountered this same issue. Like TrevorBradley, we've implemented a workaround wherein we have a helper function that does the additional Paragraph revision filtering right after the query runs, but it would be great to have this resolved (or even to have a better workaround, if anyone knows of one). Thanks for the work on this so far everyone!

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

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

neclimdul’s picture

Status: Needs work » Needs review
StatusFileSize
new8.21 KB
new1.04 KB

I was struggling with default_content bugs and revision failures as part of #2698425: Do not re-import existing entities and finally and finally started digging into the entity system and fell into this. Oh man that hurts.

Here's a reroll of #25 working around a bunch of code moving to DefaultTableMapping and moving the update hook.

One other interdiff, I removed the logic exception addition in EntityFieldManager. Even with the update hook, I needed a container rebuild but the rebuild failed building the field definitions. Maybe there's a way to keep that but it seemed like a super painful update. Maybe a deprecation notice would be better? I don't know....

Lets see how tests go. Hopefully just the field changes from the previous patch.

Status: Needs review » Needs work

The last submitted patch, 35: 27766135-reroll-25.patch, failed testing. View results

neclimdul’s picture

That failed pretty terribly. the revision field is completely removed from entity definitions. I assume I botched rerolling but maybe there's been some fundamental change that breaks this approach. I was dodging quite a few commits trying to resolve where changes where suppose to go and I'm not clear on how the fix works so 50/50 on where the blame lies. If someone who understands the approach wants to give some pointers I can take another stab at fixing this.

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

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

gordon’s picture

StatusFileSize
new7.83 KB
new1.6 KB

Rerolled again as it was not applying.

dhirendra.mishra’s picture

Status: Needs work » Needs review

@gordon. Make sure to move status needs review after applying patch.

Status: Needs review » Needs work

The last submitted patch, 39: 2766135-39.patch, failed testing. View results

amateescu’s picture

Status: Needs work » Needs review
Issue tags: -Entity query, -Needs tests
StatusFileSize
new960 bytes
new2.8 KB

Making the revision ID field revisionable seems a bit risky at this point, and, since it's a "special" field (like the ID, UUID and bundle fields), I don't see why we shouldn't hardcode it in entity query itself.

The last submitted patch, 42: 2766135-42-test-only.patch, failed testing. View results

hchonov’s picture

Making the revision ID field revisionable seems a bit risky at this point, and, since it's a "special" field (like the ID, UUID and bundle fields), I don't see why we shouldn't hardcode it in entity query itself.

This is fair enough and I agree.

However, we should still have a follow-up to make the revision ID field revisionable at some point and then refactor the entity query code.

hchonov’s picture

Nice, thank you. So we just now need someone to RTBC, however from my point of view we are ready here!

+1 on RTBC.

daffie’s picture

Status: Needs review » Reviewed & tested by the community

The code looks good.
The documentation is in order.
The test tests what is should test.
The bug from the IS will be fixed, small little fix.
For me it is RTBC.

The last submitted patch, 42: 2766135-42-test-only.patch, failed testing. View results

The last submitted patch, 42: 2766135-42-test-only.patch, failed testing. View results

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.

  • catch committed f717ef8 on 9.1.x
    Issue #2766135 by hchonov, jeroen.b, amateescu, neclimdul, gordon,...

  • catch committed 9972f46 on 9.0.x
    Issue #2766135 by hchonov, jeroen.b, amateescu, neclimdul, gordon,...

  • catch committed f685001 on 8.9.x
    Issue #2766135 by hchonov, jeroen.b, amateescu, neclimdul, gordon,...
catch’s picture

Version: 9.1.x-dev » 8.9.x-dev
Status: Reviewed & tested by the community » Fixed

Committed/pushed to 9.1.x and backported through to 8.9.x, thanks!

joseph.olstad’s picture

Thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.