Fix ALTER COLUMN TYPE bug: it sometimes tried to drop UNIQUE or PRIMARY KEY
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 30 Jan 2006 16:19:12 +0000 (16:19 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 30 Jan 2006 16:19:12 +0000 (16:19 +0000)
constraints before FOREIGN KEY constraints that depended on them.  Originally
reported by Neil Conway on 29-Jun-2005.  Patch by Nakano Yoshihisa.

src/backend/commands/tablecmds.c

index 20c6437897aa40868319d18814a6999fdfa62196..bc28c5968319a91857a04e92dd85684141606fc2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.142.4.4 2005/10/03 02:45:25 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.142.4.5 2006/01/30 16:19:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -4926,12 +4926,38 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 
            case OCLASS_CONSTRAINT:
                Assert(foundObject.objectSubId == 0);
-               if (!list_member_oid(tab->changedConstraintOids, foundObject.objectId))
+               if (!list_member_oid(tab->changedConstraintOids,
+                                    foundObject.objectId))
                {
-                   tab->changedConstraintOids = lappend_oid(tab->changedConstraintOids,
-                                                  foundObject.objectId);
-                   tab->changedConstraintDefs = lappend(tab->changedConstraintDefs,
-                     pg_get_constraintdef_string(foundObject.objectId));
+                   char *defstring = pg_get_constraintdef_string(foundObject.objectId);
+
+                   /*
+                    * Put NORMAL dependencies at the front of the list and
+                    * AUTO dependencies at the back.  This makes sure that
+                    * foreign-key constraints depending on this column will
+                    * be dropped before unique or primary-key constraints of
+                    * the column; which we must have because the FK
+                    * constraints depend on the indexes belonging to the
+                    * unique constraints.
+                    */
+                   if (foundDep->deptype == DEPENDENCY_NORMAL)
+                   {
+                       tab->changedConstraintOids =
+                           lcons_oid(foundObject.objectId,
+                                     tab->changedConstraintOids);
+                       tab->changedConstraintDefs =
+                           lcons(defstring,
+                                 tab->changedConstraintDefs);
+                   }
+                   else
+                   {
+                       tab->changedConstraintOids =
+                           lappend_oid(tab->changedConstraintOids,
+                                       foundObject.objectId);
+                       tab->changedConstraintDefs =
+                           lappend(tab->changedConstraintDefs,
+                                   defstring);
+                   }
                }
                break;
 
@@ -5099,10 +5125,12 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab)
        ATPostAlterTypeParse((char *) lfirst(l), wqueue);
 
    /*
-    * Now we can drop the existing constraints and indexes ---
-    * constraints first, since some of them might depend on the indexes.
-    * It should be okay to use DROP_RESTRICT here, since nothing else
-    * should be depending on these objects.
+    * Now we can drop the existing constraints and indexes --- constraints
+    * first, since some of them might depend on the indexes.  In fact, we
+    * have to delete FOREIGN KEY constraints before UNIQUE constraints,
+    * but we already ordered the constraint list to ensure that would happen.
+    * It should be okay to use DROP_RESTRICT here, since nothing else should
+    * be depending on these objects.
     */
    if (tab->changedConstraintOids)
        obj.classId = get_system_catalog_relid(ConstraintRelationName);