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

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

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

Backport of 6c3dfba89215fc56fc27ef61829a6fff88be4abb from master.
This commit is contained in:
Simon Charette 2019-09-15 23:25:50 -04:00 committed by Mariusz Felisiak
parent 30c3d5fd73
commit fd393907c9
5 changed files with 19 additions and 5 deletions

View File

@ -86,7 +86,7 @@ class KeyTransform(Transform):
def as_sql(self, compiler, connection): def as_sql(self, compiler, connection):
lhs, params = compiler.compile(self.lhs) 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(object): class KeyTransformFactory(object):

View File

@ -107,7 +107,7 @@ class KeyTransform(Transform):
lookup = int(self.key_name) lookup = int(self.key_name)
except ValueError: except ValueError:
lookup = self.key_name 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): class KeyTextTransform(KeyTransform):

View File

@ -9,4 +9,6 @@ Django 1.11.25 fixes a regression in 1.11.23.
Bugfixes 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

@ -5,7 +5,7 @@ import json
from django.core import exceptions, serializers from django.core import exceptions, serializers
from django.db import connection 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.forms import Form
from django.test.utils import CaptureQueriesContext, modify_settings from django.test.utils import CaptureQueriesContext, modify_settings
@ -189,6 +189,12 @@ class TestQuerying(HStoreTestCase):
queries[0]['sql'], 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])
class TestSerialization(HStoreTestCase): class TestSerialization(HStoreTestCase):
test_data = ('[{"fields": {"field": "{\\"a\\": \\"b\\"}"}, ' test_data = ('[{"fields": {"field": "{\\"a\\": \\"b\\"}"}, '

View File

@ -7,7 +7,7 @@ from decimal import Decimal
from django.core import exceptions, serializers from django.core import exceptions, serializers
from django.core.serializers.json import DjangoJSONEncoder from django.core.serializers.json import DjangoJSONEncoder
from django.db import connection from django.db import connection
from django.db.models import F from django.db.models import F, OuterRef, Subquery
from django.db.models.expressions import RawSQL from django.db.models.expressions import RawSQL
from django.db.models.functions import Cast from django.db.models.functions import Cast
from django.forms import CharField, Form, widgets from django.forms import CharField, Form, widgets
@ -222,6 +222,12 @@ class TestQuerying(PostgreSQLTestCase):
[self.objs[7], self.objs[8]] [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): def test_deep_lookup_objs(self):
self.assertSequenceEqual( self.assertSequenceEqual(
JSONModel.objects.filter(field__k__l='m'), JSONModel.objects.filter(field__k__l='m'),