From 3df72660560730393fc958700d2a3ab975c4b361 Mon Sep 17 00:00:00 2001 From: Jacob Kaplan-Moss Date: Mon, 25 Aug 2008 12:56:06 +0000 Subject: [PATCH] Fixed #3575: use UPPER() instead ILIKE for postgres case-insensitive comparisons. git-svn-id: http://code.djangoproject.com/svn/django/trunk@8536 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/backends/postgresql/base.py | 8 ++++---- django/db/backends/postgresql/operations.py | 16 ++++++++++++---- django/db/backends/postgresql_psycopg2/base.py | 8 ++++---- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py index 7bcda5b6f6..376d7ba2c8 100644 --- a/django/db/backends/postgresql/base.py +++ b/django/db/backends/postgresql/base.py @@ -70,9 +70,9 @@ class DatabaseFeatures(BaseDatabaseFeatures): class DatabaseWrapper(BaseDatabaseWrapper): operators = { 'exact': '= %s', - 'iexact': 'ILIKE %s', + 'iexact': '= UPPER(%s)', 'contains': 'LIKE %s', - 'icontains': 'ILIKE %s', + 'icontains': 'LIKE UPPER(%s)', 'regex': '~ %s', 'iregex': '~* %s', 'gt': '> %s', @@ -81,8 +81,8 @@ class DatabaseWrapper(BaseDatabaseWrapper): 'lte': '<= %s', 'startswith': 'LIKE %s', 'endswith': 'LIKE %s', - 'istartswith': 'ILIKE %s', - 'iendswith': 'ILIKE %s', + 'istartswith': 'LIKE UPPER(%s)', + 'iendswith': 'LIKE UPPER(%s)', } def __init__(self, *args, **kwargs): diff --git a/django/db/backends/postgresql/operations.py b/django/db/backends/postgresql/operations.py index 4eb5ead47c..01cc1fc8b7 100644 --- a/django/db/backends/postgresql/operations.py +++ b/django/db/backends/postgresql/operations.py @@ -36,10 +36,18 @@ class DatabaseOperations(BaseDatabaseOperations): return " DEFERRABLE INITIALLY DEFERRED" def lookup_cast(self, lookup_type): - if lookup_type in ('iexact', 'contains', 'icontains', 'startswith', 'istartswith', - 'endswith', 'iendswith'): - return "%s::text" - return "%s" + lookup = '%s' + + # Cast text lookups to text to allow things like filter(x__contains=4) + if lookup_type in ('iexact', 'contains', 'icontains', 'startswith', + 'istartswith', 'endswith', 'iendswith'): + lookup = "%s::text" + + # Use UPPER(x) for case-insensitive lookups; it's faster. + if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith'): + lookup = 'UPPER(%s)' % lookup + + return lookup def field_cast_sql(self, db_type): if db_type == 'inet': diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py index 61e440f577..6ecf86b705 100644 --- a/django/db/backends/postgresql_psycopg2/base.py +++ b/django/db/backends/postgresql_psycopg2/base.py @@ -40,9 +40,9 @@ class DatabaseOperations(PostgresqlDatabaseOperations): class DatabaseWrapper(BaseDatabaseWrapper): operators = { 'exact': '= %s', - 'iexact': 'ILIKE %s', + 'iexact': '= UPPER(%s)', 'contains': 'LIKE %s', - 'icontains': 'ILIKE %s', + 'icontains': 'LIKE UPPER(%s)', 'regex': '~ %s', 'iregex': '~* %s', 'gt': '> %s', @@ -51,8 +51,8 @@ class DatabaseWrapper(BaseDatabaseWrapper): 'lte': '<= %s', 'startswith': 'LIKE %s', 'endswith': 'LIKE %s', - 'istartswith': 'ILIKE %s', - 'iendswith': 'ILIKE %s', + 'istartswith': 'LIKE UPPER(%s)', + 'iendswith': 'LIKE UPPER(%s)', } def __init__(self, *args, **kwargs):