#31109 closed Bug (fixed)
Multiple annotation with Subquery generates wrong SQL.
Reported by: | Thierry Bastian | Owned by: | Simon Charette |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 3.0 |
Severity: | Release blocker | Keywords: | |
Cc: | Simon Charette | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I have 2 models Item and ItemInfo.
class Item(models.Model): name = TextField() ... class ItemInfo(models.Model): id = models.OneToOneField(Item, models.CASCADE, db_column='id', primary_key=True) size = models.BigIntegerField(blank=True, null=True) ...
If I do a QuerySet like this:
Item.objects \ .annotate( size=Subquery( ItemInfo.objects.filter(id=OuterRef('id')).values_list( 'size', flat=True )[:1] ), depends_on=StringAgg('name', ', ' ) )
If I simply execute it, it works. Please don't look at the QuerySet, I really tried to make it the simplest example ever
But if I do a .exists() I'm getting
django.db.utils.ProgrammingError: column "size" does not exist
LINE 1...
Obviously that used to work with any 2.x version.
Change History (7)
comment:1 by , 5 years ago
comment:2 by , 5 years ago
Severity: | Normal → Release blocker |
---|---|
Triage Stage: | Unreviewed → Accepted |
I reproduced the issue in the current master (abeb4599af5ea7a384e18ec6201a95c9e419b44a).
This regression seems to have been caused by fb3f034f1c63160c0ff13c609acd01c18be12f80 (found using git bisect
).
I'll bump the severity to "release blocker" because of the regression.
Thanks!
comment:3 by , 5 years ago
Cc: | added |
---|---|
Summary: | multiple annotation with SubQuery generates wrong SQL → Multiple annotation with Subquery generates wrong SQL. |
comment:4 by , 5 years ago
So here's what happens here.
- Since
StringAgg
is an aggregate it setsqueryset.query.group_by = True
on annotation. QuerySet.exists()
relies onQuery.has_results
Query.has_results
does the following whendistinct=False
andgroup_by=True
.- It adds all the the concrete fields of the model to address #24835
- Calls
set_group_by
which happens to add aRef
referring to the selectedSubquery
annotation togroup_by
since fb3f034f1c63160c0ff13c609acd01c18be12f80 . - It then calls
clear_select_clause
which orphans theRef
since it now points to column that isn't referenced to anymore.
The solutions is either to:
- Add a parameter to
Query.set_group_by
to preventGROUP BY
by aliases; effectively passingalias=None
to all itsannotation.get_group_by_cols
calls. - Make
clear_select_clause
remove allRef
toannotation_select
entries fromgroup_by
before callingset_annotation_mask(())
.
- is likely less invasive and seems more correct given the sole caller requiring this behaviour does so because it knows it'll call
clear_select_clause
right after.
comment:5 by , 5 years ago
Has patch: | set |
---|---|
Owner: | changed from | to
Status: | new → assigned |
Could this be a duplicate of #31094? Maybe you could try with that patch applied?