#31615: Do not fail migration if postgresql extension is already installed and 
user
is not superuser
-------------------------------------+-------------------------------------
               Reporter:  minusf     |          Owner:  nobody
                   Type:  Bug        |         Status:  new
              Component:             |        Version:  3.0
  Migrations                         |       Keywords:  migration extension
               Severity:  Normal     |  postgresql
           Triage Stage:             |      Has patch:  1
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  1
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 Currently Django facilitates installing postgres extensions using
 migration operations:
 https://docs.djangoproject.com/en/3.0/ref/contrib/postgres/operations/

 But having a superuser is a tall order in certain environments, and the
 manual helpfully points out:

 If the Django database user doesn’t have superuser privileges, you’ll have
 to create the extension outside of Django migrations with a user that has
 the appropriate privileges.

 This is fairly often the case with Salt and other orchestration systems.

 However having a non-superuser will break any migrations using these
 operations because unfortunately `CREATE EXTENSION` even with `IF NOT
 EXISTS` still requires superuser privileges... In other words, if the
 extension is already in place, the migration will fail...

 I think a failsafe like this around CREATE/DROP EXTENSION would make the
 migrations more robust and user friendly.

 {{{
 diff --git a/django/contrib/postgres/operations.py
 b/django/contrib/postgres/operations.py
 index 0bb131ddf2..46fc11f63f 100644
 --- a/django/contrib/postgres/operations.py
 +++ b/django/contrib/postgres/operations.py
 @@ -21,7 +21,13 @@ class CreateExtension(Operation):
              not router.allow_migrate(schema_editor.connection.alias,
 app_label)
          ):
              return
 -        schema_editor.execute("CREATE EXTENSION IF NOT EXISTS %s" %
 schema_editor.quote_name(self.name))
 +
 +        cur = schema_editor.connection.cursor()
 +        cur.execute("SELECT * FROM pg_extension WHERE extname = %s",
 [self.name])
 +        if not cur.fetchone():
 +            schema_editor.execute(
 +                "CREATE EXTENSION IF NOT EXISTS %s" %
 schema_editor.quote_name(self.name)
 +            )
          # Clear cached, stale oids.
          get_hstore_oids.cache_clear()
          get_citext_oids.cache_clear()
 @@ -33,7 +39,13 @@ class CreateExtension(Operation):
      def database_backwards(self, app_label, schema_editor, from_state,
 to_state):
          if not router.allow_migrate(schema_editor.connection.alias,
 app_label):
              return
 -        schema_editor.execute("DROP EXTENSION %s" %
 schema_editor.quote_name(self.name))
 +
 +        cur = schema_editor.connection.cursor()
 +        cur.execute("SELECT * FROM pg_extension WHERE extname = %s",
 [self.name])
 +        if cur.fetchone():
 +            schema_editor.execute(
 +                "DROP EXTENSION %s" % schema_editor.quote_name(self.name)
 +            )
          # Clear cached, stale oids.
          get_hstore_oids.cache_clear()
          get_citext_oids.cache_clear()
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/31615>
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 django-updates+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/049.d4a7512325c3974cbc631d30dc90716f%40djangoproject.com.

Reply via email to