#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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/049.d4a7512325c3974cbc631d30dc90716f%40djangoproject.com.

Reply via email to