diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py index ad6c504261..9de9b44735 100644 --- a/django/db/backends/postgresql/base.py +++ b/django/db/backends/postgresql/base.py @@ -121,7 +121,7 @@ class DatabaseWrapper(BaseDatabaseWrapper): # # Note: we use str.format() here for readability as '%' is used as a wildcard for # the LIKE operator. - pattern_esc = r"REPLACE(REPLACE(REPLACE({}, '\', '\\'), '%%', '\%%'), '_', '\_')" + pattern_esc = r"REPLACE(REPLACE(REPLACE({}, E'\\', E'\\\\'), E'%%', E'\\%%'), E'_', E'\\_')" pattern_ops = { 'contains': "LIKE '%%' || {} || '%%'", 'icontains': "LIKE '%%' || UPPER({}) || '%%'", diff --git a/tests/postgres_tests/test_unaccent.py b/tests/postgres_tests/test_unaccent.py index 018aedb64c..ae7027713c 100644 --- a/tests/postgres_tests/test_unaccent.py +++ b/tests/postgres_tests/test_unaccent.py @@ -42,6 +42,28 @@ class UnaccentTest(PostgreSQLTestCase): ordered=False ) + def test_unaccent_chained_with_conforming_strings_off(self): + """ + Chained unaccent causes the comparison string to be escaped. + Make sure the escaping SQL is valid even if the DB has standard_conforming_strings OFF. + """ + from django.db import connection + cur = connection.cursor() + cur.execute("SET standard_conforming_strings TO OFF;") + self.assertQuerysetEqual( + self.Model.objects.filter(field__unaccent__iexact="aeO"), + ["àéÖ", "aeO", "aeo"], + transform=lambda instance: instance.field, + ordered=False + ) + self.assertQuerysetEqual( + self.Model.objects.filter(field__unaccent__endswith="éÖ"), + ["àéÖ", "aeO"], + transform=lambda instance: instance.field, + ordered=False + ) + cur.execute("SET standard_conforming_strings TO ON;") + def test_unaccent_accentuated_needle(self): self.assertQuerysetEqual( self.Model.objects.filter(field__unaccent="aéÖ"),