Fixed #30332 -- Fixed crash of ordering by expressions with params in ArrayAgg and StringAgg.

This commit is contained in:
Simone Pellizzari 2019-04-06 13:45:22 +02:00 committed by Mariusz Felisiak
parent 47a1f2a06f
commit d0315584b5
No known key found for this signature in database
GPG Key ID: 2EF56372BA48CD1B
3 changed files with 24 additions and 6 deletions

View File

@ -21,13 +21,17 @@ class OrderableAggMixin:
def as_sql(self, compiler, connection): def as_sql(self, compiler, connection):
if self.ordering: if self.ordering:
self.extra['ordering'] = 'ORDER BY ' + ', '.join(( ordering_params = []
ordering_element.as_sql(compiler, connection)[0] ordering_expr_sql = []
for ordering_element in self.ordering for expr in self.ordering:
expr_sql, expr_params = expr.as_sql(compiler, connection)
ordering_expr_sql.append(expr_sql)
ordering_params.extend(expr_params)
sql, sql_params = super().as_sql(compiler, connection, ordering=(
'ORDER BY ' + ', '.join(ordering_expr_sql)
)) ))
else: return sql, sql_params + ordering_params
self.extra['ordering'] = '' return super().as_sql(compiler, connection, ordering='')
return super().as_sql(compiler, connection)
def get_source_expressions(self): def get_source_expressions(self):
return self.source_expressions + self.ordering return self.source_expressions + self.ordering

View File

@ -17,3 +17,8 @@ Bugfixes
* Fixed a regression in Django 2.2 that caused a crash when loading the * Fixed a regression in Django 2.2 that caused a crash when loading the
template for the technical 500 debug page (:ticket:`30324`). template for the technical 500 debug page (:ticket:`30324`).
* Fixed crash of ``ordering`` argument in
:class:`~django.contrib.postgres.aggregates.ArrayAgg` and
:class:`~django.contrib.postgres.aggregates.StringAgg` when it contains an
expression with params (:ticket:`30332`).

View File

@ -1,6 +1,7 @@
import json import json
from django.db.models.expressions import F, Value from django.db.models.expressions import F, Value
from django.db.models.functions import Concat, Substr
from django.test.utils import Approximate from django.test.utils import Approximate
from . import PostgreSQLTestCase from . import PostgreSQLTestCase
@ -37,6 +38,12 @@ class TestGeneralAggregate(PostgreSQLTestCase):
((F('boolean_field'), F('char_field').desc()), ['Foo4', 'Foo2', 'Foo3', 'Foo1']), ((F('boolean_field'), F('char_field').desc()), ['Foo4', 'Foo2', 'Foo3', 'Foo1']),
('char_field', ['Foo1', 'Foo2', 'Foo3', 'Foo4']), ('char_field', ['Foo1', 'Foo2', 'Foo3', 'Foo4']),
('-char_field', ['Foo4', 'Foo3', 'Foo2', 'Foo1']), ('-char_field', ['Foo4', 'Foo3', 'Foo2', 'Foo1']),
(Concat('char_field', Value('@')), ['Foo1', 'Foo2', 'Foo3', 'Foo4']),
(Concat('char_field', Value('@')).desc(), ['Foo4', 'Foo3', 'Foo2', 'Foo1']),
(
(Substr('char_field', 1, 1), F('integer_field'), Substr('char_field', 4, 1).desc()),
['Foo3', 'Foo1', 'Foo2', 'Foo4'],
),
) )
for ordering, expected_output in ordering_test_cases: for ordering, expected_output in ordering_test_cases:
with self.subTest(ordering=ordering, expected_output=expected_output): with self.subTest(ordering=ordering, expected_output=expected_output):
@ -166,6 +173,8 @@ class TestGeneralAggregate(PostgreSQLTestCase):
(F('char_field'), 'Foo1;Foo2;Foo3;Foo4'), (F('char_field'), 'Foo1;Foo2;Foo3;Foo4'),
('char_field', 'Foo1;Foo2;Foo3;Foo4'), ('char_field', 'Foo1;Foo2;Foo3;Foo4'),
('-char_field', 'Foo4;Foo3;Foo2;Foo1'), ('-char_field', 'Foo4;Foo3;Foo2;Foo1'),
(Concat('char_field', Value('@')), 'Foo1;Foo2;Foo3;Foo4'),
(Concat('char_field', Value('@')).desc(), 'Foo4;Foo3;Foo2;Foo1'),
) )
for ordering, expected_output in ordering_test_cases: for ordering, expected_output in ordering_test_cases:
with self.subTest(ordering=ordering, expected_output=expected_output): with self.subTest(ordering=ordering, expected_output=expected_output):