Ticket #1186 (new defect)

Opened 3 years ago

Last modified 3 years ago

mysql _lookup_constraint_references can return None, expected to return iterable.

Reported by: stephen@… Owned by: andrew
Priority: major Milestone:
Component: migrations Version: mercurial
Keywords: Cc:


During column renaming, _lookup_contraint_references is called and the return value is directly assigned to a tuple. [1] Unfortunately, _lookup_constraint_references sometimes returns None. [2] I suppose this is probably "never supposed to happen" but I've run into it multiple times when working with renaming columns in m2m through tables.

[1] https://bitbucket.org/andrewgodwin/south/src/463114da627da10946aa0ae42a8b5745f302633a/south/db/mysql.py?at=default#cl-41

[2] https://bitbucket.org/andrewgodwin/south/src/463114da627da10946aa0ae42a8b5745f302633a/south/db/mysql.py?at=default#cl-234

Change History

comment:1 Changed 3 years ago by bouke@…

Also ran into this bug today. There is a simple fix, however requires you to change the codebase. See also #1233.

comment:2 Changed 3 years ago by bouke@…

So I monkey patched South in the failing migration:

        def _lookup_constraint_references(self, table_name, cname):
            Provided an existing table and constraint, returns tuple of (foreign
            table, column)
            db_name = self._get_setting('NAME')
                return self._constraint_references[db_name][(table_name, cname)]
            except KeyError:
                raise IndexError  # would normally return None, see upstream #1186
        mysql.DatabaseOperations._lookup_constraint_references = _lookup_constraint_references

comment:3 Changed 3 years ago by stephen@…

I've also run into this issue. It's causing migrations to fail consistently on MySQL.


comment:4 Changed 3 years ago by stephen@…

Hah. Actually, I was the person who originally reported this issue five months ago. It's just been so long that I forgot. :-p

comment:5 Changed 3 years ago by anonymous

We see this problem too.



how to reproduce

The following migration

class Migration(SchemaMigration):

    def forwards(self, orm):
        db.rename_column('my_app_table', 'list_id',

    def backwards(self, orm):
        db.rename_column('my_app_tabe', 'list_RENAMED_id', 'list_id')



Crashes with the following error.

- Migrating forwards to 0016_rename_list.
 > epcrm_campaigns:0016_rename_list
 ! Error found during real run of migration! Aborting.

 ! Since you have a database that does not support running
 ! schema-altering statements in transactions, we have had 
 ! to leave it in an interim state between migrations.

! You *might* be able to recover with:   - no dry run output for delete_foreign_key() due to dynamic DDL, sorry

 ! The South developers regret this has happened, and would
 ! like to gently persuade you to consider a slightly
 ! easier-to-deal-with DBMS (one that supports DDL transactions)
 ! NOTE: The error which caused the migration to fail is further up.
Error in migration: my_app:0016_rename_list
Traceback (most recent call last):

  File "...opt/python2.6/lib/python2.6/site-packages/south/migration/migrators.py", line 310, in migrate_many
    result = self.migrate(migration, database)
  File "...opt/python2.6/lib/python2.6/site-packages/south/migration/migrators.py", line 133, in migrate
    result = self.run(migration)
  File "...opt/python2.6/lib/python2.6/site-packages/south/migration/migrators.py", line 107, in run
    return self.run_migration(migration)
  File "...opt/python2.6/lib/python2.6/site-packages/south/migration/migrators.py", line 81, in run_migration
  File "...opt/python2.6/lib/python2.6/site-packages/south/migration/migrators.py", line 57, in <lambda>
    return (lambda: direction(orm))
  File "...projects/platform/django/apps/my_app/migrations/0016_rename_list.py", line 14, in forwards
  File "...opt/python2.6/lib/python2.6/site-packages/south/db/mysql.py", line 41, in _column_cp
    (ftable, fcolumn) = self._lookup_constraint_references(table_name, constraint)
TypeError: 'NoneType' object is not iterable


Rerunning ./manage.py migrate succeeds.

We see this over and over again.

(crash, try again -> works)

Note: See TracTickets for help on using tickets.