[3.0.x] Fixed #30769 -- Fixed a crash when filtering against a subquery JSON/HStoreField annotation.

This was a regression introduced by 7deeabc7c7
to address CVE-2019-14234.

Thanks Tim Kleinschmidt for the report and Mariusz for the tests.

Backport of 6c3dfba892 from master
This commit is contained in:
Simon Charette 2019-09-15 23:25:50 -04:00 committed by Mariusz Felisiak
parent 7bd28727ad
commit 574154ef56
7 changed files with 27 additions and 6 deletions

View File

@ -86,7 +86,7 @@ class KeyTransform(Transform):
def as_sql(self, compiler, connection):
lhs, params = compiler.compile(self.lhs)
return '(%s -> %%s)' % lhs, params + [self.key_name]
return '(%s -> %%s)' % lhs, tuple(params) + (self.key_name,)
class KeyTransformFactory:

View File

@ -112,7 +112,7 @@ class KeyTransform(Transform):
lookup = int(self.key_name)
except ValueError:
lookup = self.key_name
return '(%s %s %%s)' % (lhs, self.operator), params + [lookup]
return '(%s %s %%s)' % (lhs, self.operator), tuple(params) + (lookup,)
class KeyTextTransform(KeyTransform):

View File

@ -9,4 +9,6 @@ Django 1.11.25 fixes a regression in 1.11.23.
Bugfixes
========
* ...
* Fixed a crash when filtering with a ``Subquery()`` annotation of a queryset
containing :class:`~django.contrib.postgres.fields.JSONField` or
:class:`~django.contrib.postgres.fields.HStoreField` (:ticket:`30769`).

View File

@ -9,4 +9,6 @@ Django 2.1.13 fixes a regression in 2.1.11.
Bugfixes
========
* ...
* Fixed a crash when filtering with a ``Subquery()`` annotation of a queryset
containing :class:`~django.contrib.postgres.fields.JSONField` or
:class:`~django.contrib.postgres.fields.HStoreField` (:ticket:`30769`).

View File

@ -11,3 +11,8 @@ Bugfixes
* Fixed migrations crash on SQLite when altering a model containing partial
indexes (:ticket:`30754`).
* Fixed a regression in Django 2.2.4 that caused a crash when filtering with a
``Subquery()`` annotation of a queryset containing
:class:`~django.contrib.postgres.fields.JSONField` or
:class:`~django.contrib.postgres.fields.HStoreField` (:ticket:`30769`).

View File

@ -2,7 +2,7 @@ import json
from django.core import checks, exceptions, serializers
from django.db import connection
from django.db.models.expressions import RawSQL
from django.db.models.expressions import OuterRef, RawSQL, Subquery
from django.forms import Form
from django.test.utils import CaptureQueriesContext, isolate_apps
@ -207,6 +207,12 @@ class TestQuerying(PostgreSQLTestCase):
queries[0]['sql'],
)
def test_obj_subquery_lookup(self):
qs = HStoreModel.objects.annotate(
value=Subquery(HStoreModel.objects.filter(pk=OuterRef('pk')).values('field')),
).filter(value__a='b')
self.assertSequenceEqual(qs, self.objs[:2])
@isolate_apps('postgres_tests')
class TestChecks(PostgreSQLSimpleTestCase):

View File

@ -6,7 +6,7 @@ from decimal import Decimal
from django.core import checks, exceptions, serializers
from django.core.serializers.json import DjangoJSONEncoder
from django.db import connection
from django.db.models import Count, F, Q
from django.db.models import Count, F, OuterRef, Q, Subquery
from django.db.models.expressions import RawSQL
from django.db.models.functions import Cast
from django.forms import CharField, Form, widgets
@ -303,6 +303,12 @@ class TestQuerying(PostgreSQLTestCase):
[self.objs[7], self.objs[8]]
)
def test_obj_subquery_lookup(self):
qs = JSONModel.objects.annotate(
value=Subquery(JSONModel.objects.filter(pk=OuterRef('pk')).values('field')),
).filter(value__a='b')
self.assertSequenceEqual(qs, [self.objs[7], self.objs[8]])
def test_deep_lookup_objs(self):
self.assertSequenceEqual(
JSONModel.objects.filter(field__k__l='m'),