Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Fix possible "tuple concurrently updated" error in ALTER TABLE.
authorRobert Haas <rhaas@postgresql.org>
Sat, 19 Mar 2011 02:09:57 +0000 (22:09 -0400)
committerRobert Haas <rhaas@postgresql.org>
Sat, 19 Mar 2011 02:09:57 +0000 (22:09 -0400)
When adding an inheritance parent to a table, an AccessShareLock on the
parent isn't strong enough to prevent trouble, so take
ShareUpdateExclusiveLock instead.  Since this is a behavior change,
albeit a fairly unobtrusive one, and since we have only one report
from the field, no back-patch.

Report by Jon Nelson, analysis by Alvaro Herrera, fix by me.

src/backend/commands/tablecmds.c

index f1264bfb66d61595eea92274bd107674f8898397..ee34cfa97e15030678b15ae2c034a9430c960939 100644 (file)
@@ -1345,7 +1345,14 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
        AttrNumber *newattno;
        AttrNumber  parent_attno;
 
-       relation = heap_openrv(parent, AccessShareLock);
+       /*
+        * A self-exclusive lock is needed here.  If two backends attempt to
+        * add children to the same parent simultaneously, and that parent has
+        * no pre-existing children, then both will attempt to update the
+        * parent's relhassubclass field, leading to a "tuple concurrently
+        * updated" error.
+        */
+       relation = heap_openrv(parent, ShareUpdateExclusiveLock);
 
        if (relation->rd_rel->relkind != RELKIND_RELATION)
            ereport(ERROR,
@@ -7942,10 +7949,10 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
    List       *children;
 
    /*
-    * AccessShareLock on the parent is what's obtained during normal CREATE
-    * TABLE ... INHERITS ..., so should be enough here.
+    * A self-exclusive lock is needed here.  See the similar case in
+    * MergeAttributes() for a full explanation.
     */
-   parent_rel = heap_openrv(parent, AccessShareLock);
+   parent_rel = heap_openrv(parent, ShareUpdateExclusiveLock);
 
    /*
     * Must be owner of both parent and child -- child was checked by