]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Lock the extension during ALTER EXTENSION ADD/DROP.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 11 Jul 2021 16:54:24 +0000 (12:54 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 11 Jul 2021 16:54:24 +0000 (12:54 -0400)
Although we were careful to lock the object being added or dropped,
we failed to get any sort of lock on the extension itself.  This
allowed the ALTER to proceed in parallel with a DROP EXTENSION,
which is problematic for a couple of reasons.  If both commands
succeeded we'd be left with a dangling link in pg_depend, which
would cause problems later.  Also, if the ALTER failed for some
reason, it might try to print the extension's name, and that could
result in a crash or (in older branches) a silly error message
complaining about extension "(null)".

Per bug #17098 from Alexander Lakhin.  Back-patch to all
supported branches.

Discussion: https://postgr.es/m/17098-b960f3616c861f83@postgresql.org

src/backend/commands/extension.c

index 7a2f2fd6fa3b218a847802d9c8a0dea683db09de..f3f44b7f6de0f8bf1f09dd54fc9fced8fa744531 100644 (file)
@@ -3200,9 +3200,17 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
        Relation        relation;
        Oid                     oldExtension;
 
-       extension.classId = ExtensionRelationId;
-       extension.objectId = get_extension_oid(stmt->extname, false);
-       extension.objectSubId = 0;
+       /*
+        * Find the extension and acquire a lock on it, to ensure it doesn't get
+        * dropped concurrently.  A sharable lock seems sufficient: there's no
+        * reason not to allow other sorts of manipulations, such as add/drop of
+        * other objects, to occur concurrently.  Concurrently adding/dropping the
+        * *same* object would be bad, but we prevent that by using a non-sharable
+        * lock on the individual object, below.
+        */
+       extension = get_object_address(OBJECT_EXTENSION,
+                                                                  (Node *) makeString(stmt->extname),
+                                                                  &relation, AccessShareLock, false);
 
        /* Permission check: must own extension */
        if (!pg_extension_ownercheck(extension.objectId, GetUserId()))