mirror of
https://github.com/doctrine/orm.git
synced 2026-03-23 22:42:18 +01:00
Paginator fails with $fetchJoinCollection = true and query ordered by a join column.
#7018
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @joaquimds on GitHub (Aug 3, 2022).
Bug Report
Summary
Paginator fails with
$fetchJoinCollection = trueand query ordered by a join column.Current behavior
A query generated by the paginator is invalid, and returns an "unknown field" SQL error, because the
ORDER BY join_columnis not correctly handled.Imagine a schema as follows:
The paginator works if the
ORDER BYuses a normal field, e.g.Person.name- example DQL:The SQL looks like:
But when the
ORDER BYuses a join column, e.g.Person.house:The SQL that is generated looks like:
house_idis missing in the inner select (because it's a join column, so not in the field names of the class metadata), and it also isn't converted intoORDER BY house_id_1in the outer query (asnamewas converted in the previous example).Relevant functions are
SqlWalker::walkSelectClause, which generates the inner SELECT, andLimitSubqueryOutputWalker::recreateInnerSql, which re-applies theORDER BYclause to the outer query.How to reproduce
I will work on a reproducable example in my free time, hope to get it to you soon.
Expected behavior
The paginator should be able to sort by join columns. In fact, it does work if
$fetchJoinCollection = false.@joaquimds commented on GitHub (Aug 3, 2022):
I can get around this issue by manually telling Doctrine to use the standard
SqlWalkerinstead ofLimitSubqueryOutputWalker:This seems to work, and the pagination still works correctly, even if there are multiple child entities for each root entity (which I believe is the reason
$fetchJoinCollection = trueis needed). Which raises the question: what is the purpose ofLimitSubqueryOutputWalker? I think I'm missing something.@joaquimds commented on GitHub (Aug 10, 2022):
I have created a unit test for this and a "fix", but I can't push a branch to make a PR. The fix I have done feels dirty so I think someone who understands Doctrine better than I do should rework it.
The test is:
tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php:The fix is:
storage/code/doctrine-orm/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php@GlucNAc commented on GitHub (Oct 21, 2022):
I do reproduce this and it is clearly a breaking change bug as
$fetchJoinCollection = trueis the default value for the Paginator.@joaquimds I do have rigth to create a PR then I think you too. Even if the code is not clean, it would be the beggining of the fix :)
@petski commented on GitHub (Oct 23, 2024):
Hello from 2024 :). Found this report while investigating an issue I've came across.
The relevant part of the
QueryI supply to thePaginatorlooks like this:The
pointtype is doing something likereturn sprintf('ST_GeomFromText(%s)', $sqlExpr)in itsconvertToDatabaseValue.The
COUNT-SQLquery works as expected.The
DISTINCT ... LIMIT-SQLquery results in an invalid SQL statement: The SQLquery results inST_Distance_Sphere(s0_.geography_point, ?)instead of aST_Distance_Sphere(s0_.geography_point, ST_GeomFromText(?)). The SQLquery is invalid because of this, so resulting in a SQL exception.If, as a test, I remove the
orderByfrom the query, then all works as expected. All three (count, distinct-limit, where-in) queries are valid, apart from the ordering of course.I think "my issue" is strongly related to this report.
Setting
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, \Doctrine\ORM\Query\SqlWalker::class);is a working work-around.Replacing
LimitSubqueryOutputWalker::generateSqlAliasReplacements()with the version supplied by @joaquimds does NOT resolve my issue though.