Opened 7 years ago

Closed 4 years ago

#6386 closed (fixed)

hash() in creating db names is unpredictable, and unnecessary

Reported by: nedbatchelder Owned by: elbarto
Component: Core (Other) Version: master
Severity: Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

In this code fragment from django/core/management/sql.py:

    # For MySQL, r_name must be unique in the first 64 characters.
    # So we are careful with character usage here.
    r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
    final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
        (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),
        qn(r_col), qn(table), qn(col),
        connection.ops.deferrable_sql()))

The r_name is computed with a hash() component. This creates a shorter name, but hash() is not guaranteed to be stable across versions of Python or across 32- and 64-bit architectures. This makes the SQL produced by a model unpredictable, and a development machine and production machine in the same shop could disagree on names.

This became a problem for us when we had to write db upgrades on one machine and apply them to another. We use the SQL generation to verify that the upgrade was successful, and the difference in the names made the validation fail.

The r_name variable is eventually passed into truncate_name anyway: this function does the right thing, shortening the name by using md5 to produce a repeatable hash from the text of the name.

If we remove the hash() from the name generation, we'll have repeatable names.

Change History (3)

comment:1 Changed 7 years ago by guettli

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted

I can confirm that this is a problem. I had problems with the random name, too.

I wanted to delete a foreign key constraint (the history should remain, even if
the model instance was deleted).

I used this with postgres to get the name of the constraint:

select constraint_name from information_schema.key_column_usage where table_name='myapp_history' and column_name='mymodel_id' 

comment:2 Changed 4 years ago by elbarto

  • Owner changed from nobody to elbarto

comment:3 Changed 4 years ago by elbarto

  • Resolution set to fixed
  • Status changed from new to closed

The ticket is obsolete. It was fixed in r8296 where the database backend code was refactored.

Note: See TracTickets for help on using tickets.
Back to Top