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

Backport of d0315584b5 from master.
This commit is contained in:
Simone Pellizzari 2019-04-06 13:45:22 +02:00 committed by Mariusz Felisiak
parent 9da25fb832
commit 268ed9cd8a
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.testcases import skipUnlessDBFeature from django.test.testcases import skipUnlessDBFeature
from django.test.utils import Approximate from django.test.utils import Approximate
@ -38,6 +39,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):
@ -165,6 +172,8 @@ class TestGeneralAggregate(PostgreSQLTestCase):
(F('char_field').desc(), 'Foo4;Foo3;Foo2;Foo1'), (F('char_field').desc(), 'Foo4;Foo3;Foo2;Foo1'),
(F('char_field').asc(), 'Foo1;Foo2;Foo3;Foo4'), (F('char_field').asc(), 'Foo1;Foo2;Foo3;Foo4'),
(F('char_field'), 'Foo1;Foo2;Foo3;Foo4'), (F('char_field'), 'Foo1;Foo2;Foo3;Foo4'),
(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):