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..ccc1c53878 100644 --- a/tests/postgres_tests/test_unaccent.py +++ b/tests/postgres_tests/test_unaccent.py @@ -1,3 +1,4 @@ +from django.db import connection, DatabaseError from django.test import modify_settings from . import PostgreSQLTestCase @@ -42,6 +43,24 @@ 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. + """ + with connection.cursor() as cur: + cur.execute("SET standard_conforming_strings TO OFF;") + try: + self.assertQuerysetEqual( + self.Model.objects.filter(field__unaccent__endswith="éÖ"), + ["àéÖ", "aeO"], + transform=lambda instance: instance.field, + ordered=False + ) + except DatabaseError: + self.fail("DatabaseError should not have occurred.") + cur.execute("SET standard_conforming_strings TO ON;") + def test_unaccent_accentuated_needle(self): self.assertQuerysetEqual( self.Model.objects.filter(field__unaccent="aéÖ"),