From f1ea26dd99415d376ab0e170bfce75fcfdeb7c01 Mon Sep 17 00:00:00 2001 From: Justin Bronn Date: Sat, 19 Dec 2009 08:19:38 +0000 Subject: [PATCH] Fixed #12234 -- Create additional indexes that use the appropriate operation class for PostgreSQL `varchar` and `text` columns when `db_index=True`. git-svn-id: http://code.djangoproject.com/svn/django/trunk@11912 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/backends/postgresql/creation.py | 39 +++++++++++++++++++++++ docs/ref/databases.txt | 15 +++++++++ 2 files changed, 54 insertions(+) diff --git a/django/db/backends/postgresql/creation.py b/django/db/backends/postgresql/creation.py index 0940c7eb71..be7f49482b 100644 --- a/django/db/backends/postgresql/creation.py +++ b/django/db/backends/postgresql/creation.py @@ -35,3 +35,42 @@ class DatabaseCreation(BaseDatabaseCreation): if settings.TEST_DATABASE_CHARSET: return "WITH ENCODING '%s'" % settings.TEST_DATABASE_CHARSET return '' + + def sql_indexes_for_field(self, model, f, style): + if f.db_index and not f.unique: + qn = self.connection.ops.quote_name + db_table = model._meta.db_table + tablespace = f.db_tablespace or model._meta.db_tablespace + if tablespace: + sql = self.connection.ops.tablespace_sql(tablespace) + if sql: + tablespace_sql = ' ' + sql + else: + tablespace_sql = '' + else: + tablespace_sql = '' + + def get_index_sql(index_name, opclass=''): + return (style.SQL_KEYWORD('CREATE INDEX') + ' ' + + style.SQL_TABLE(qn(index_name)) + ' ' + + style.SQL_KEYWORD('ON') + ' ' + + style.SQL_TABLE(qn(db_table)) + ' ' + + "(%s%s)" % (style.SQL_FIELD(qn(f.column)), opclass) + + "%s;" % tablespace_sql) + + output = [get_index_sql('%s_%s' % (db_table, f.column))] + + # Fields with database column types of `varchar` and `text` need + # a second index that specifies their operator class, which is + # needed when performing correct LIKE queries outside the + # C locale. See #12234. + db_type = f.db_type() + if db_type.startswith('varchar'): + output.append(get_index_sql('%s_%s_like' % (db_table, f.column), + ' varchar_pattern_ops')) + elif db_type.startswith('text'): + output.append(get_index_sql('%s_%s_like' % (db_table, f.column), + ' text_pattern_ops')) + else: + output = [] + return output diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt index fc58dbaf47..d7ae120f94 100644 --- a/docs/ref/databases.txt +++ b/docs/ref/databases.txt @@ -80,6 +80,21 @@ You should also audit your existing code for any instances of this behavior before enabling this feature. It's faster, but it provides less automatic protection for multi-call operations. +Indexes for ``varchar`` and ``text`` columns +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. versionadded:: 1.1.2 + +When specifying ``db_index=True`` on your model fields, Django typically +outputs a single ``CREATE INDEX`` statement. However, if the database type +for the field is either ``varchar`` or ``text`` (e.g., used by ``CharField``, +``FileField``, and ``TextField``), then Django will create +an additional index that uses an appropriate `PostgreSQL operator class`_ +for the column. The extra index is necessary to correctly perfrom +lookups that use the ``LIKE`` operator in their SQL, as is done with the +``contains`` and ``startswith`` lookup types. + +.. _PostgreSQL operator class: http://www.postgresql.org/docs/8.4/static/indexes-opclass.html + .. _mysql-notes: MySQL notes