Fixed #35744 -- Relabelled external aliases of combined queries.

Just like normal queries, combined queries' outer references might fully
resolve before their reference is assigned its final alias.

Refs #29338.

Thanks Antony_K for the report and example, and thanks Mariusz Felisiak
for the review.
This commit is contained in:
Simon Charette 2024-10-14 19:21:48 -04:00 committed by GitHub
parent 97c05a64ca
commit 53ea4cce2f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 41 additions and 1 deletions

View File

@ -1021,11 +1021,21 @@ class Query(BaseExpression):
if alias == old_alias: if alias == old_alias:
table_aliases[pos] = new_alias table_aliases[pos] = new_alias
break break
# 3. Rename the direct external aliases and the ones of combined
# queries (union, intersection, difference).
self.external_aliases = { self.external_aliases = {
# Table is aliased or it's being changed and thus is aliased. # Table is aliased or it's being changed and thus is aliased.
change_map.get(alias, alias): (aliased or alias in change_map) change_map.get(alias, alias): (aliased or alias in change_map)
for alias, aliased in self.external_aliases.items() for alias, aliased in self.external_aliases.items()
} }
for combined_query in self.combined_queries:
external_change_map = {
alias: aliased
for alias, aliased in change_map.items()
if alias in combined_query.external_aliases
}
combined_query.change_aliases(external_change_map)
def bump_prefix(self, other_query, exclude=None): def bump_prefix(self, other_query, exclude=None):
""" """

View File

@ -14,7 +14,16 @@ from django.db.models.functions import Mod
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
from django.test.utils import CaptureQueriesContext from django.test.utils import CaptureQueriesContext
from .models import Author, Celebrity, ExtraInfo, Number, ReservedName from .models import (
Annotation,
Author,
Celebrity,
ExtraInfo,
Note,
Number,
ReservedName,
Tag,
)
@skipUnlessDBFeature("supports_select_union") @skipUnlessDBFeature("supports_select_union")
@ -450,6 +459,27 @@ class QuerySetSetOperationTests(TestCase):
[8, 1], [8, 1],
) )
@skipUnlessDBFeature("supports_select_intersection")
def test_intersection_in_nested_subquery(self):
tag = Tag.objects.create(name="tag")
note = Note.objects.create(tag=tag)
annotation = Annotation.objects.create(tag=tag)
tags = Tag.objects.order_by()
tags = tags.filter(id=OuterRef("tag_id")).intersection(
tags.filter(id=OuterRef(OuterRef("tag_id")))
)
qs = Note.objects.filter(
Exists(
Annotation.objects.filter(
Exists(tags),
notes__in=OuterRef("pk"),
)
)
)
self.assertIsNone(qs.first())
annotation.notes.add(note)
self.assertEqual(qs.first(), note)
def test_union_in_subquery_related_outerref(self): def test_union_in_subquery_related_outerref(self):
e1 = ExtraInfo.objects.create(value=7, info="e3") e1 = ExtraInfo.objects.create(value=7, info="e3")
e2 = ExtraInfo.objects.create(value=5, info="e2") e2 = ExtraInfo.objects.create(value=5, info="e2")