-
Notifications
You must be signed in to change notification settings - Fork 11.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[8.x] Incorrect FQCN for withAggregate() on self-relation #35389
Conversation
PS. In my app I've started using |
The reason was described in #35061 (comment) When using the feature on a I'm sorry, if this introduced another bug. Is there a way to access the aliases for that kind of relation? Will check on that. |
@dbakan & @khalilst, big thanks to both of you for joining the effort, and thanks for your earlier contributions! So the qualification was needed to handle aggregates on My other option was to move the qualification to later, in the The other way around, to somehow "guess" the alias before |
@bjuppa @dbakan @driesvints |
Just create a fresh pr if you have to thanks. |
@khalilst Thank you very much! |
@dbakan My pleasure. @driesvints Sorry for bothering. I have to include the test provided here by @bjuppa in #35392 ? |
This PR provides a failing test case for when methods in the
withAggregate()
-family are used on an Eloquent "self-relation".Aggregate queries on self-relations use a generated table alias, but the aggregate column will fail to be qualified to that alias, silently producing incorrect results, or an sql-error when
sql_mode=only_full_group_by
.I not sure yet what the solution would be, but hopefully this failing-test PR can be a starting point to discuss a good approach!
Background
Laravel
8.13
included b0dc0b2 that added$relation->getRelated()->qualifyColumn($column)
to qualify the column name in the aggregate subquery. This seems reasonable as that column name used to end up unqualified, and that is of course a risk.Unfortunately the introduced qualification is done before knowing what the actual table alias will be in the final query.
It will always qualify using the table name from the relation for the aggregate column.
This goes unnoticed for common relationships between two different models, each with their own table...
What goes wrong?
For a relationship that references the same model (e.g. a student tutoring other students), the table in the subquery is aliased (see example in
HasOneOrMany
– variants are in other relationship types too).So, the "child"-table of the subquery becomes aliased (a generated hash), while the selected aggregate column in the very same sub-query is still qualified to what at this point is actually the "parent" table. 😞
Example sql
This reflects current sql produced when
->withMin('created_at')
is used on a self-relationship:Sql error looks something like this:
In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'test_db.self_related_stubs.id'; this is incompatible with sql_mode=only_full_group_by
Possible solutions
Can we go back to not qualifying the aggregate column?
Between
8.12
(when the super-usefulwithAggregate
-methods were introduced in 95d0c9a, thanks @khalilst!) and8.13
, aggregates on self-relations worked as expected (at least with mysql 8 that I've been running). The column name wasn't qualified at all and there was just a single from-table in the actual subquery part, so I guess it was unambiguous.illuminate/database
?What can we do if we want to keep the FQCN?
getRelationExistenceQueryForSelfRelation
, where the final alias is in scope?illuminate/database
? So that one can pass an object containing an unqualified column name, indicating that builder methods may qualify at the point they're actually used in queries... This may not make sense... 🤔 I just made it up! 😄Thanks for reading, and thanks for collaborating on this wonderful framework! Please share your thoughts on how we can solve this!