#29345: Migrations that recreate constraints can fail on PostgreSQL if table is 
not
in public schema
---------------------------------------+------------------------
               Reporter:  Olav Morken  |          Owner:  nobody
                   Type:  Bug          |         Status:  new
              Component:  Migrations   |        Version:  2.0
               Severity:  Normal       |       Keywords:
           Triage Stage:  Unreviewed   |      Has patch:  0
    Needs documentation:  0            |    Needs tests:  0
Patch needs improvement:  0            |  Easy pickings:  0
                  UI/UX:  0            |
---------------------------------------+------------------------
 The
 `django.db.backends.postgresql.introspection.get_constraints(...)`-function
 contains an SQL expression that assumes that all tables are in the
 `public` schema:
 
https://github.com/django/django/blob/2.0.4/django/db/backends/postgresql/introspection.py#L178-L201

 The last few lines read:

 {{{
             JOIN pg_class AS cl ON c.conrelid = cl.oid
             JOIN pg_namespace AS ns ON cl.relnamespace = ns.oid
             WHERE ns.nspname = %s AND cl.relname = %s
         """, ["public", table_name])
 }}}

 The result is that it fails to find any constraints for tables that are
 not in the `public` schema. This either leaves us with two identical
 constraints, when it fails to delete the old, or results in an exception
 when it subsequently tries to recreate a constraint that it should have
 deleted:

 {{{
 django.db.utils.ProgrammingError: constraint
 "migration_app_testref_test_id_bce0807a_fk" for relation
 "migration_app_testref" already exists
 }}}

 A simple fix is to not check for the `public` schema, but instead check
 visibility using `pg_catalog.pg_table_is_visible(cl.oid)`:

 {{{
             JOIN pg_class AS cl ON c.conrelid = cl.oid
             WHERE cl.relname = %s AND
 pg_catalog.pg_table_is_visible(cl.oid)
         """, ["public", table_name])
 }}}

 This appears to give the correct result, even when there are multiple
 tables with the same name in the database.

 I have attached a migration file and models file for a simple app
 `migration_app` that reproduces this problem. To be able to reproduce it,
 you must use a custom schema search path when connecting to PostgreSQL,
 either by setting it as the default for the role, or by specifying it in
 the connection options:

 {{{
 DATABASES = {
     'default': {
         'ENGINE': 'django.db.backends.postgresql_psycopg2',
         'NAME': 'migration_test',
         'HOST': 'localhost',
         'USER': 'postgres',
         'OPTIONS': {
             'options': '-c search_path=testschema,public',
         },
     }
 }
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/29345>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/050.2035eacb67fcca4e2e476a5f6b1ac4a8%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to