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.
SelectQuery::countQuery() tries to ensure there will be one field but with UNION queries each SELECT needs to have the exact same field definitions. In the case of a query with !empty($this->union) we should skip this step.
Comments
Comment #1
hass CreditAttribution: hass commented+
Comment #2
drewish CreditAttribution: drewish commentedHere's a test case. Setting to NR to for the testbot.
Comment #4
reujwils CreditAttribution: reujwils commentedI have also come across this issue in 7.4.
Comment #5
mwallenberg CreditAttribution: mwallenberg commentedThis problem still exists in 7.12.
Comment #6
David_Rothstein CreditAttribution: David_Rothstein commentedHere's a possible fix for the bug, added to the tests from #2. I actually tried to fix this by ensuring that each individual SELECT query in the UNION is rewritten down to 1 field in the same way as the first query is. It seemed to work in my testing.
This will need to be moved to Drupal 8, but here are patches for Drupal 7 for starters to let the testbot run against them first.
Comment #7
David_Rothstein CreditAttribution: David_Rothstein commentedPatches for Drupal 8.
Comment #8
hosef CreditAttribution: hosef commentedTests got moved around when Drupal got PSR-0ed, so the D8 patches no longer apply. It should be just a matter of finding where the database tests ended up and rerolling.
I am going to test the D7 patches, even though they can't go in till the D8 patches are fixed.
Comment #9
ZenDoodles CreditAttribution: ZenDoodles commented#7: core-union-count-query-1145080-7-TESTS-ONLY.patch queued for re-testing.
Comment #10
ZenDoodles CreditAttribution: ZenDoodles commented#7: core-union-count-query-1145080-7.patch queued for re-testing.
Comment #12
hosef CreditAttribution: hosef commentedI just tested the D7 patches in all three supported databases and it works for all of them. I will be rerolling the D8 patches soon.
Comment #13
hosef CreditAttribution: hosef commentedOk, here are the new D8 patches for this. The only modification that I made was to change the path to the new test location. I have tested them in all three supported databases.
Comment #14
hosef CreditAttribution: hosef commentedMarking 'needs review'.
Comment #16
hosef CreditAttribution: hosef commentedI knew the first one would fail, why are you marking my post as 'needs work' silly System Message. :)
Comment #17
xjmLooks great to me. Couple minor docs points we can adjust:
We should add a docblock for this since we are updating it. Check to see if this method exists in the base class or interface and add the appropriate one-line docblock if so.
Should say "Tests."
An inline comment or two here might be nice.
-3 days to next Drupal core point release.
Comment #18
Noe_ CreditAttribution: Noe_ commentedA patch with a little more docs.
Update: This is just a patch of the patch isn't it?
Comment #20
hosef CreditAttribution: hosef commented#18: core-union-count-query-1145080-14.patch queued for re-testing.
Comment #21
hosef CreditAttribution: hosef commentedI believe the test fail was related to #1655422: Random test failures in SearchCommentTest, and has nothing to do with this patch.
The new Docs look fine to me, it applies, and I have already done several tests on PostgreSQL and SQLite to make sure it works there, so I think that this can be marked RTBC.
Comment #22
Dries CreditAttribution: Dries commentedWouldn't this test be better if the second query used a value other than 27 or 28?
Comment #23
ZenDoodles CreditAttribution: ZenDoodles commentedYes, but since that value is hard coded throughout the select tests, the change would be much more far reaching than this patch. I opened #1703418: Use test values other than 27 for age.
Comment #24
hosef CreditAttribution: hosef commentedI changed the condition in the second query to be 29 and the test still passed
@Dries, is that what you wanted?
Comment #25
Noe_ CreditAttribution: Noe_ commentedI don't think so, because in my opinion the test needs at least one duplicate value in there to see that that duplicate value in not duplicated in the result.
However there could be another value in there, such as:
Comment #26
xjmMinor points for cleanup during today's office hours:
Does this method override a method on the parent class? If not, all we need to do is change "Get" to "Gets". If so, we should move these docs to the parent method instead.
This is the hunk where we should change "Test" to "Tests". :)
This change is outside the scope of the patch and should be reverted.
Comment #27
xjmWe are limited to the values that are provided in the installed schema. @ZenDoodles and I spoke about this last week.
Comment #28
Noe_ CreditAttribution: Noe_ commentedI have fixed everything that xjm mentioned.
Here is the new patch.
Comment #29
hosef CreditAttribution: hosef commentedMarked as needs review so that the testbot can run.
Comment #30
bigjim CreditAttribution: bigjim commented+1 for this patch it's a show stopper for an effort to re-vitalize the Views Union module #1789796: Pager applied to the View based on the parent Display. Looks like it's RTBC, marking it as such.
Comment #31
bigjim CreditAttribution: bigjim commentedD7 version of the #28 patch.
Comment #33
bigjim CreditAttribution: bigjim commentedUgh! No good deed goes unpunished :) I didn't mean to set off the test bot with my D7 version of the patch in #31.
So to be clear
#28 = D8 patch
#31 is D7 patch
restting to RTBC.
Comment #34
catchThis looks fine to me. Committed/pushed to 8.x, moving to 7.x for backport.
Comment #35
star-szr#31: core-union-count-query-1145080-31-D7.patch queued for re-testing.
Comment #37
bigjim CreditAttribution: bigjim commentedUpon further review the test in the patch for D8 is retuning a false positive. Further the patch in #28 doesn't actually fix the problem as the result of countQuery() will always = 1.
In the test the UNION query will read something like this:
For both queries the result is 1 which means the result from the query is a single row with the value 1 as the UNION will automatically merge the duplicates. The test compares the count of fields which is always 1 with the value from fetchField() upon the first, and only, row which is a 1. Consequently the test cannot fail. The beauty of the patch in #28 is the # of fields will always be the same thus avoiding the most common issue with UNION statements, but it's simply not realistic :(
patches for D8 and D7 attached
Comment #38
catchDon't we need to update the tests as well then?
Comment #39
bigjim CreditAttribution: bigjim commented@catch, no as the test subquery kicked out by the countQuery() method will now look like this:
which will result in a count of 2.
Sorry my post may have mislead a bit. The real issue lies in the #28 patch not the test. It occurs to me we are not calling prepareCountQuery() recursively in my proposed patch so we could pull it out, not sure if it matters though.
Comment #40
bigjim CreditAttribution: bigjim commentedThese patches take out the prepareCountQuery() method, as it's not necessary. Either #40 or #37 will fix the original issue.
I have a possibly naive protocol question. #1145076: UNION queries don't support ORDER BY clauses is a related issue as it's dealing with DBTNG bugs with UNION queries and in the same file. Should it be merged with this patch?
Comment #41
bigjim CreditAttribution: bigjim commentedmoving to RTBC.
I'll repost the D7 patch on it's own and re-roll #1145076: UNION queries don't support ORDER BY clauses once this is committed to D8
Comment #42
webchickPlease don't RTBC your own patch.
Comment #43
bigjim CreditAttribution: bigjim commentedMy bad, I guess now I understand why core developers are always begging for people to review patches on podcasts, in blogs and such.
Comment #44
webchickHaha yep :D You might want to stop by #drupal-contribute on IRC sometime, there's also a lot of people who engage in "patch review swapping" to help each other out.
Comment #45
David_Rothstein CreditAttribution: David_Rothstein commentedHm, I'm pretty sure the original patch I posted worked fine in the case of UNION ALL (which admittedly was the only situation I was even thinking about at the time... oops :)
So given that the existing test uses UNION ALL (and therefore should already work fine), perhaps we also need a test for regular UNION (a.k.a. UNION DISTINCT)? It should be possible to write one that fails currently but passes with the new patch.
I guess this is OK, although I'm not totally clear when it's OK to skip everything inside that if() statement (probably one of the reasons I tried not to change it originally!). Is that if() statement just a performance improvement? If so, it should be fine to skip, although if possible I'd think it would be nice to keep this behavior around in the case of UNION ALL, since as mentioned I above I believe UNION DISTINCT is the only place where there's a bug here anymore; UNION ALL should already work fine.
Either way, the code comment above (as well as the one below it, in the
addExpression('1')
part) should probably be expanded to mention what's going on with the union queries here. It's some pretty confusing stuff.Comment #46
bigjim CreditAttribution: bigjim commentedI'll work on the comment.
The main reason I skipped the if() is to avoid changing the fields in individual queries which could result in different fields in the individual queries for either UNION ALL or DISTINCT especially in cases where one of the queries has a GROUP BY that is no in others (admittedly an uncommon use case but then so is UNION ALL :)).
Comment #50
daffie CreditAttribution: daffie commentedIn Drupal\KernelTests\Core\Database\SelectTest we have the test:
For D8 is this issue fixed. The tag "needs backport to D7" is attached. So I am putting this one back to D7.
Comment #51
stefan.r CreditAttribution: stefan.r commentedComment #56
eojthebravePer #37, I think this is still a bug in Drupal 8. Count queries work for
UNION ALL
, but notUNION
queries.I've been working on a Drupal 7 project that's using
$query->union()
and this is also still a bug in Drupal 7 for bothUNION ALL
andUNION
. It prevents you from being able to create a pager query with a union.To answer the question in #45, as far as I can tell yes, removing those fields from the WHERE clause is to improve performance. The patch in #37 appears to be a more appropriate fix than the one that was committed as it solves for both
UNION ALL
andUNION
.Comment #57
David_Rothstein CreditAttribution: David_Rothstein as a volunteer commentedComment #61
Rob230 CreditAttribution: Rob230 as a volunteer and at CTI Digital commentedThis is indeed still broken if you use
$query->union($secondQuery)
. The count query always returns 1.It works fine for
$query->union($secondQuery, 'ALL')
.Should another bug be raised? I know this is an 8 year old issue that everybody considers resolved...
Comment #64
daffie CreditAttribution: daffie commented@Rob320: Please create new issue when you have a bug.
Comment #65
daffie CreditAttribution: daffie commentedComment #66
jeffschulerSpecifying the "ALL" union type made my D7->D10 migration's counts actually meaningful. This is still a lingering issue.