Opened 7 years ago

Last modified 11 days ago

#28646 new Bug

Migration calls "CREATE INDEX" when one already exists when 'unique' field attribute is added — at Version 1

Reported by: Hari - 何瑞理 Owned by: nobody
Component: Migrations Version: 1.11
Severity: Normal Keywords: postgresql, migration, index, #djangocph
Cc: Tomer Chachamu, bcail Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Hari - 何瑞理)

PostgreSQL migration automatically creates an index for fields that set db_index=True. An example is SlugField, which sets this property implicitly. Thereafter when the unique=True property is added to the field the resultant migration script generates an AlterField object to apply this unique attribute. The schema editor then incorrectly detects this new unique=True attribute to indicate the need to create a like index statement on the field which causes an error as it conflicts with the already existing index.

The offending piece of code seems to be at django/db/backends/postgresql/schema.py:117.

 if ((not (old_field.db_index or old_field.unique) and new_field.db_index) or
                (not old_field.unique and new_field.unique)):
            like_index_statement = self._create_like_index_sql(model, new_field)
            if like_index_statement is not None:
                self.execute(like_index_statement)

If it's changed as:

 if (not (old_field.db_index or old_field.unique) and (new_field.db_index or new_field.unique)):
            like_index_statement = self._create_like_index_sql(model, new_field)
            if like_index_statement is not None:
                self.execute(like_index_statement)

this error won't occur.

PostgreSQL 9.5 introduces IF NOT EXISTS to the CREATE INDEX statement which if added to the schema template can also address this problem without changing the above logic.

I encountered the problem with SlugField() which implicitly sets db_index=True on PostgreSQL 9.4.

Interestingly, I only discovered this when I used django-tenant-schemas which adds a thin layer on top of the default Database router setting the schema search path before handing over the work to the default router. With a vanilla Django installation using default router, the second call to create a like index does not throw an error. However, upon reviewing the code, the logic does look incorrect. Also issuing the duplicate SQL statement in PostgreSQL console also throws an error.

I'm still investigating to see if this there's more to this than what I just described.

Change History (1)

comment:1 by Hari - 何瑞理, 7 years ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top