Hi,

Please find the patch attached.  This is for the bug which is posted to
hackers before.
http://archives.postgresql.org/pgsql-hackers/2005-06/msg01442.php

We can see a problem by this bug in following way.

CREATE TABLE pktable (a int primary key);
CREATE TABLE fktable (b int references pktable);
ALTER TABLE pktable ALTER COLUMN a TYPE bigint;  -- succeed
REINDEX TABLE pg_depend;
ALTER TABLE pktable ALTER COLUMN a TYPE int;     -- fail
NOTICE:  constraint fktable_b_fkey on table fktable depends on index
pktable_pkey
ERROR:  cannot drop constraint pktable_pkey on table pktable because
other objects depend on it
HINT:  Use DROP ... CASCADE to drop the dependent objects too.


I changed the order of constraints list to delete foreign key
constraints first.

Any comments are welcome.

Regards,
Nakano


*** postgresql-8.1.2-org/src/backend/commands/tablecmds.c       2005-11-23 
03:23:07.000000000 +0900
--- postgresql-8.1.2/src/backend/commands/tablecmds.c   2006-01-27 
21:46:54.000000000 +0900
***************
*** 4970,4979 ****
                                Assert(foundObject.objectSubId == 0);
                                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));
                                }
                                break;
  
--- 4970,5022 ----
                                Assert(foundObject.objectSubId == 0);
                                if 
(!list_member_oid(tab->changedConstraintOids, foundObject.objectId))
                                {
!                                       Oid conOid = foundObject.objectId;
!                                       Relation conRel;
!                                       SysScanDesc conScan;
!                                       ScanKeyData conKey[1];
!                                       HeapTuple conTup;
!                                       Form_pg_constraint conForm;
!                                       char *defstring = 
pg_get_constraintdef_string(foundObject.objectId);
! 
!                                       /* Look up the target constraint */
!                                       conRel = 
heap_open(ConstraintRelationId, AccessShareLock);
! 
!                                       ScanKeyInit(&conKey[0],
!                                                               
ObjectIdAttributeNumber,
!                                                               
BTEqualStrategyNumber, F_OIDEQ,
!                                                               
ObjectIdGetDatum(conOid));
! 
!                                       conScan = systable_beginscan(conRel, 
ConstraintOidIndexId, true,
!                                                                               
                 SnapshotNow, 1, conKey);
! 
!                                       /* This should not fail, since 
pg_get_constraint_string found it. */
!                                       conTup = systable_getnext(conScan);
! 
!                                       conForm = (Form_pg_constraint) 
GETSTRUCT(conTup);
! 
!                                       /*
!                                        * FOREIGN KEY constraints depend on 
the indexes which are depend
!                                        * on PRIMARY KEY constraints, so we 
need to append FOREIGN KEY
!                                        * constraints ahead of PRIMARY KEY 
constraints.  Otherwise deletion
!                                        * of a PRIMARY KEY constraint with 
RESTRICT in cleanup will fail.
!                                        */
!                                       if (conForm->contype == 
CONSTRAINT_FOREIGN)
!                                       {
!                                               tab->changedConstraintOids = 
lcons_oid(conOid,
!                                                                               
                                           tab->changedConstraintOids);
!                                               tab->changedConstraintDefs = 
lcons(defstring,
!                                                                               
                                   tab->changedConstraintDefs);
!                                       }
!                                       else
!                                       {
!                                               tab->changedConstraintOids = 
lappend_oid(tab->changedConstraintOids,
!                                                                               
                                                 conOid);
!                                               tab->changedConstraintDefs = 
lappend(tab->changedConstraintDefs,
!                                                                               
                                         defstring);
!                                       }
! 
!                                       systable_endscan(conScan);
!                                       heap_close(conRel, AccessShareLock);
                                }
                                break;
  
***************
*** 5141,5149 ****
  
        /*
         * 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.
         */
        foreach(l, tab->changedConstraintOids)
        {
--- 5184,5193 ----
  
        /*
         * Now we can drop the existing constraints and indexes --- constraints
!        * first, since some of them might depend on the indexes.  (FOREIGN KEY
!        * constraints depend on the indexes, but these are deleted first.)
!        * It should be okay to use DROP_RESTRICT here, since nothing else 
should
!        * be depending on these objects.
         */
        foreach(l, tab->changedConstraintOids)
        {
---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster

Reply via email to