Fixed #30488 -- Removed redundant Coalesce call in SQL generated by SearchVector.

Regression in 405c836336.
This commit is contained in:
Thomasina Lee 2019-05-17 15:27:01 +01:00 committed by Mariusz Felisiak
parent 04042b2b44
commit c38e7a79f4
3 changed files with 23 additions and 14 deletions

View File

@ -60,14 +60,6 @@ class SearchVector(SearchVectorCombinable, Func):
def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False): def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
resolved = super().resolve_expression(query, allow_joins, reuse, summarize, for_save) resolved = super().resolve_expression(query, allow_joins, reuse, summarize, for_save)
resolved.set_source_expressions([
Coalesce(
expression
if isinstance(expression.output_field, (CharField, TextField))
else Cast(expression, TextField()),
Value('')
) for expression in resolved.get_source_expressions()
])
if self.config: if self.config:
if not hasattr(self.config, 'resolve_expression'): if not hasattr(self.config, 'resolve_expression'):
resolved.config = Value(self.config).resolve_expression(query, allow_joins, reuse, summarize, for_save) resolved.config = Value(self.config).resolve_expression(query, allow_joins, reuse, summarize, for_save)
@ -76,17 +68,26 @@ class SearchVector(SearchVectorCombinable, Func):
return resolved return resolved
def as_sql(self, compiler, connection, function=None, template=None): def as_sql(self, compiler, connection, function=None, template=None):
clone = self.copy()
clone.set_source_expressions([
Coalesce(
expression
if isinstance(expression.output_field, (CharField, TextField))
else Cast(expression, TextField()),
Value('')
) for expression in clone.get_source_expressions()
])
config_params = [] config_params = []
if template is None: if template is None:
if self.config: if clone.config:
config_sql, config_params = compiler.compile(self.config) config_sql, config_params = compiler.compile(clone.config)
template = '%(function)s({}::regconfig, %(expressions)s)'.format(config_sql.replace('%', '%%')) template = '%(function)s({}::regconfig, %(expressions)s)'.format(config_sql.replace('%', '%%'))
else: else:
template = self.template template = clone.template
sql, params = super().as_sql(compiler, connection, function=function, template=template) sql, params = super(SearchVector, clone).as_sql(compiler, connection, function=function, template=template)
extra_params = [] extra_params = []
if self.weight: if clone.weight:
weight_sql, extra_params = compiler.compile(self.weight) weight_sql, extra_params = compiler.compile(clone.weight)
sql = 'setweight({}, {})'.format(sql, weight_sql) sql = 'setweight({}, {})'.format(sql, weight_sql)
return sql, config_params + params + extra_params return sql, config_params + params + extra_params

View File

@ -14,3 +14,7 @@ Bugfixes
* Fixed a regression in Django 2.2 where deprecation message crashes if * Fixed a regression in Django 2.2 where deprecation message crashes if
``Meta.ordering`` contains an expression (:ticket:`30463`). ``Meta.ordering`` contains an expression (:ticket:`30463`).
* Fixed a regression in Django 2.2.1 where
:class:`~django.contrib.postgres.search.SearchVector` generates SQL with a
redundant ``Coalesce`` call (:ticket:`30488`).

View File

@ -113,6 +113,10 @@ class SearchVectorFieldTest(GrailTestData, PostgreSQLTestCase):
searched = Line.objects.filter(dialogue_search_vector=SearchQuery('cadeaux', config='french')) searched = Line.objects.filter(dialogue_search_vector=SearchQuery('cadeaux', config='french'))
self.assertSequenceEqual(searched, [self.french]) self.assertSequenceEqual(searched, [self.french])
def test_single_coalesce_expression(self):
searched = Line.objects.annotate(search=SearchVector('dialogue')).filter(search='cadeaux')
self.assertNotIn('COALESCE(COALESCE', str(searched.query))
class MultipleFieldsTest(GrailTestData, PostgreSQLTestCase): class MultipleFieldsTest(GrailTestData, PostgreSQLTestCase):