Refs #32096 -- Fixed __in lookup crash against key transforms for JSONField.

Regression in 6789ded0a6 and
1251772cb8.

Thanks Simon Charette and Igor Jerosimić for the report.
This commit is contained in:
Mariusz Felisiak 2020-10-13 11:35:55 +02:00
parent 1f31027bb3
commit 7e1e198494
4 changed files with 33 additions and 20 deletions

View File

@ -369,27 +369,26 @@ class KeyTransformIsNull(lookups.IsNull):
class KeyTransformIn(lookups.In): class KeyTransformIn(lookups.In):
def process_rhs(self, compiler, connection): def resolve_expression_parameter(self, compiler, connection, sql, param):
rhs, rhs_params = super().process_rhs(compiler, connection) sql, params = super().resolve_expression_parameter(
if not connection.features.has_native_json_field: compiler, connection, sql, param,
func = () )
if (
not hasattr(param, 'as_sql') and
not connection.features.has_native_json_field
):
if connection.vendor == 'oracle': if connection.vendor == 'oracle':
func = [] value = json.loads(param)
for value in rhs_params: if isinstance(value, (list, dict)):
value = json.loads(value) sql = "JSON_QUERY(%s, '$.value')"
function = 'JSON_QUERY' if isinstance(value, (list, dict)) else 'JSON_VALUE' else:
func.append("%s('%s', '$.value')" % ( sql = "JSON_VALUE(%s, '$.value')"
function, params = (json.dumps({'value': value}),)
json.dumps({'value': value}),
))
func = tuple(func)
rhs_params = ()
elif connection.vendor == 'mysql' and connection.mysql_is_mariadb:
func = ("JSON_UNQUOTE(JSON_EXTRACT(%s, '$'))",) * len(rhs_params)
elif connection.vendor in {'sqlite', 'mysql'}: elif connection.vendor in {'sqlite', 'mysql'}:
func = ("JSON_EXTRACT(%s, '$')",) * len(rhs_params) sql = "JSON_EXTRACT(%s, '$')"
rhs = rhs % func if connection.vendor == 'mysql' and connection.mysql_is_mariadb:
return rhs, rhs_params sql = 'JSON_UNQUOTE(%s)' % sql
return sql, params
class KeyTransformExact(JSONExact): class KeyTransformExact(JSONExact):

View File

@ -241,7 +241,7 @@ class FieldGetDbPrepValueIterableMixin(FieldGetDbPrepValueMixin):
if hasattr(param, 'resolve_expression'): if hasattr(param, 'resolve_expression'):
param = param.resolve_expression(compiler.query) param = param.resolve_expression(compiler.query)
if hasattr(param, 'as_sql'): if hasattr(param, 'as_sql'):
sql, params = param.as_sql(compiler, connection) sql, params = compiler.compile(param)
return sql, params return sql, params
def batch_process_rhs(self, compiler, connection, rhs=None): def batch_process_rhs(self, compiler, connection, rhs=None):

View File

@ -26,3 +26,7 @@ Bugfixes
:class:`~django.contrib.postgres.aggregates.JSONBAgg`, and :class:`~django.contrib.postgres.aggregates.JSONBAgg`, and
:class:`~django.contrib.postgres.aggregates.StringAgg` with ``ordering`` :class:`~django.contrib.postgres.aggregates.StringAgg` with ``ordering``
on key transforms for :class:`~django.db.models.JSONField` (:ticket:`32096`). on key transforms for :class:`~django.db.models.JSONField` (:ticket:`32096`).
* Fixed a regression in Django 3.1 that caused a crash of ``__in`` lookup when
using key transforms for :class:`~django.db.models.JSONField` in the lookup
value (:ticket:`32096`).

View File

@ -700,6 +700,16 @@ class TestQuerying(TestCase):
('value__0__in', [1], [self.objs[5]]), ('value__0__in', [1], [self.objs[5]]),
('value__0__in', [1, 3], [self.objs[5]]), ('value__0__in', [1, 3], [self.objs[5]]),
('value__foo__in', ['bar'], [self.objs[7]]), ('value__foo__in', ['bar'], [self.objs[7]]),
(
'value__foo__in',
[KeyTransform('foo', KeyTransform('bax', 'value'))],
[self.objs[7]],
),
(
'value__foo__in',
[KeyTransform('foo', KeyTransform('bax', 'value')), 'baz'],
[self.objs[7]],
),
('value__foo__in', ['bar', 'baz'], [self.objs[7]]), ('value__foo__in', ['bar', 'baz'], [self.objs[7]]),
('value__bar__in', [['foo', 'bar']], [self.objs[7]]), ('value__bar__in', [['foo', 'bar']], [self.objs[7]]),
('value__bar__in', [['foo', 'bar'], ['a']], [self.objs[7]]), ('value__bar__in', [['foo', 'bar'], ['a']], [self.objs[7]]),