Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
1. Install latest HEAD (8.7.x) with minimal profile.
2. Enable workspaces, toolbar modules
3. Visit admin/content
4. Change workspace from 'live' to 'stage' (user get redirected to user/1 page)
5. Try to visit admin/content again
Expected:
6. See content listing page
Actual:
6. See 'The website encountered an unexpected error.' After including settings.local.php
, would get:
The website encountered an unexpected error. Please try again later.</br></br><em class="placeholder">Drupal\Core\Database\DatabaseExceptionWrapper</em>: SQLSTATE[42000]: Syntax error or access violation: 1140 Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause: SELECT min(node_field_data.nid) AS expression, COALESCE(workspace_association.target_entity_revision_id, base_table.vid) AS vid, base_table.nid AS nid
FROM
{node} base_table
LEFT OUTER JOIN {workspace_association} workspace_association ON workspace_association.target_entity_type_id = 'node' AND workspace_association.target_entity_id = base_table.nid AND workspace_association.workspace = 'stage'
LEFT JOIN {node_field_data} node_field_data ON node_field_data.nid = base_table.nid
ORDER BY expression ASC
LIMIT 50 OFFSET 0; Array
(
)
in <em class="placeholder">Drupal\Core\Entity\EntityListBuilder->getEntityIds()</em> (line <em class="placeholder">104</em> of <em class="placeholder">core/lib/Drupal/Core/Entity/EntityListBuilder.php</em>). <pre class="backtrace">Drupal\Core\Database\Statement->execute(Array, Array) (Line: 625)
Drupal\Core\Database\Connection->query('SELECT min(node_field_data.nid) AS expression, COALESCE(workspace_association.target_entity_revision_id, base_table.vid) AS vid, base_table.nid AS nid
FROM
{node} base_table
LEFT OUTER JOIN {workspace_association} workspace_association ON workspace_association.target_entity_type_id = 'node' AND workspace_association.target_entity_id = base_table.nid AND workspace_association.workspace = 'stage'
LEFT JOIN {node_field_data} node_field_data ON node_field_data.nid = base_table.nid
ORDER BY expression ASC
LIMIT 50 OFFSET 0', Array, Array) (Line: 87)
Drupal\Core\Database\Driver\mysql\Connection->query('SELECT min(node_field_data.nid) AS expression, COALESCE(workspace_association.target_entity_revision_id, base_table.vid) AS vid, base_table.nid AS nid
FROM
{node} base_table
LEFT OUTER JOIN {workspace_association} workspace_association ON workspace_association.target_entity_type_id = 'node' AND workspace_association.target_entity_id = base_table.nid AND workspace_association.workspace = 'stage'
LEFT JOIN {node_field_data} node_field_data ON node_field_data.nid = base_table.nid
ORDER BY expression ASC
LIMIT 50 OFFSET 0', Array, Array) (Line: 510)
Drupal\Core\Database\Query\Select->execute() (Line: 257)
Drupal\Core\Entity\Query\Sql\Query->result() (Line: 76)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 104)
Drupal\Core\Entity\EntityListBuilder->getEntityIds() (Line: 86)
Drupal\Core\Entity\EntityListBuilder->load() (Line: 234)
Drupal\Core\Entity\EntityListBuilder->render() (Line: 23)
Drupal\Core\Entity\Controller\EntityListController->listing('node')
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 582)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 151)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 99)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 78)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 665)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
</pre>
Proposed resolution
Remaining tasks
User interface changes
API changes
Data model changes
Comment | File | Size | Author |
---|---|---|---|
#19 | Screenshot 2019-04-05 at 18.04.26.png | 118.71 KB | dixon_ |
#18 | 2987956-18.patch | 5.01 KB | amateescu |
#14 | 2987956-14.patch | 2.7 KB | mheip |
#12 | 2987956-12.patch | 2.98 KB | mariancalinro |
#12 | 2987956-12-test-only.patch | 981 bytes | mariancalinro |
Comments
Comment #2
vijaycs85Comment #3
vijaycs85Comment #5
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedThe bug here is caused by our entity query alterations, not by the workspace switching functionality :)
Comment #6
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedComment #7
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedComment #8
mariancalinro CreditAttribution: mariancalinro as a volunteer and at Dream Production commentedHere's an attempt to fix this, let's see what the tests have to say.
My approach is to take the fields we are adding to the query (id and revision fields) and add them to the GROUP BY clause too, if the query has something in the GROUP BY clause already. At the moment this only happens when sorting complex queries, but I didn't wat to use sorting as a condition, as in the future we may find there are other ways for the query to have grouping.
Comment #10
mariancalinro CreditAttribution: mariancalinro as a volunteer and at Dream Production commentedAnother atemp, it seems on some queries the GROUP BY is empty even if the aggregation functions MIN/MAX are used for sorting. For these cases we need another condition to detect if we should add the fields to the GROUP BY clause. We check if the query has sorting and it's not a simple query, specifically the case where the error happens.
Comment #12
mariancalinro CreditAttribution: mariancalinro as a volunteer and at Dream Production commentedI missed the fact that the sorting processing happens after we prepare the query, so I moved the checks to the addSort() method, after the parent method is executed. At this point we should know if we need to add or not the id fields to the GROUP BY clause.
Let's see what the tests have to say.
Comment #13
mariancalinro CreditAttribution: mariancalinro as a volunteer and at Dream Production commentedThe tests passed :)
Comment #14
mheip CreditAttribution: mheip commentedWhen I applied above patch, the issue with my entity query was indeed resolved.
The fatal error disappeared.
However, I noticed that there were a couple of issues with my entity list overviews.
Several entities were missing.
I found the issue and I'll try to explain:
Say I have 3 entities with following ids, reference ids:
|id|reference_id|
|1|1|
|2|2|
|3|5|
When I do not add sorting, the result I get is a keyed array:
Entities can then be used by doing a loadMultiple($ids);
When the EntityQuery runs it's result function, the following piece of code is called:
The FetchAllKeyed method will use index 0 as it's key index, and index 1 as it's value index.
When the SQL query is altered by workspaces, 2 expressions are added in our Workspaces Query (Drupal\workspaces\EntityQuery\Query):
And these are attached in the "finish" function:
When you don't have a sort, the result key will be the "revision" expression, and the result value will be the "id" expression.
However, when a query has a sort, this will also add an expression in the "addSort" method. And this expression will be added before the above 2 expressions. Because the expression is added in the "addSort" method instead of the "finish" method.
When you for example sort on "id" => "ASC", the following expression will be added:
Your raw result set will suddenly be:
|1|1|1|
|2|2|2|
|3|5|3|
Your keyed results will then be:
Meaning the last entity will not be found as it looks for an entity with an id of 5, which will not exist.
I have fixed this in the attached patch by adding the expressions immediately in the prepare function. It also contains the patch functionality in #12 by mariancalinro, as this is needed to avoid the fatal error.
This patch needs review and was tested on 8.6.5.
Comment #15
mallezieIn the latest patch, it seems the test coverage from #12 is missing.
Comment #16
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedThanks @mariancalinro and @mheip, the patches and the explanation from #14 are excellent detective work on the internals of entity query :)
I've just proposed a patch that changes the way entity query generates its SQL query in #2950869-30: Entity queries querying the latest revision very slow with lots of revisions. That patch also fixes this problem in Workspaces, so I've credited both of you in that issue for the helpful comments and solution here. If that patch gets in, the only goal of this issue would be to add the additional test coverage.
Comment #18
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedSince #2950869: Entity queries querying the latest revision very slow with lots of revisions doesn't have a chance of getting into 8.7.0 anymore, let's get back to fixing this in Workspaces for now.
Reading all the comments and patches again, I think we should combine the approaches from #10 and #14. The problem with sorting described in #14 can be solved by providing an override for the
isSimpleQuery()
method, and can be tested by asserting the result array of the entity query.At the moment, this bug prevents Workspaces from loading the node edit page, so I'm raising the priority to major.
Comment #19
dixon_The patch looks good and is quite simple! The additional tests adds great coverage too!
Manual testing is trivial - the node form was broken on non-live workspaces (like stage), and it's no longer broken :)
Comment #20
plachManually tested this as well, I wasn't able to get a broken form but the STR mentioned in the OP worked for me. I was a bit concerned about always adding the group by clause with complex queries but then I realized that the parent class does the same, so this change shouldn't have a performance impact.
Great detective work, guys!
Comment #24
plachCommitted 073cc74 and pushed to 8.8.x and backported to 8.7.x. Thanks!
Comment #25
plachI had to revert the initial commit as I erroneously committed/pushed to 8.7.x first instead of cherry-picking from 8.8.x. The following two commits fix this and the latter has a nice reference to the 8.8.x commit, as it should. Sorry for the confusion :)