Re: Table Inherit Problem - Mailing list pgsql-bugs

From Tom Lane
Subject Re: Table Inherit Problem
Date
Msg-id 4747.1041728374@sss.pgh.pa.us
Whole thread Raw
In response to Table Inherit Problem  ("CN" <cnliou9@fastmail.fm>)
List pgsql-bugs
"CN" <cnliou9@fastmail.fm> writes:
> db1=# update tt1 set remark ='xx';
> ERROR:  Cannot insert a duplicate key into unique index tt2_pkey

The attached patch against 7.3 fixes it.

            regards, tom lane

*** src/backend/optimizer/prep/prepunion.c.orig    Wed Sep 18 17:35:21 2002
--- src/backend/optimizer/prep/prepunion.c    Sat Jan  4 19:56:56 2003
***************
*** 67,72 ****
--- 67,73 ----
                        List *refnames_tlist);
  static Node *adjust_inherited_attrs_mutator(Node *node,
                                 adjust_inherited_attrs_context *context);
+ static List *adjust_inherited_tlist(List *tlist, Oid new_relid);


  /*
***************
*** 770,779 ****
          Query       *newnode;

          FLATCOPY(newnode, query, Query);
-         if (newnode->resultRelation == old_rt_index)
-             newnode->resultRelation = new_rt_index;
          query_tree_mutator(newnode, adjust_inherited_attrs_mutator,
                             (void *) &context, QTW_IGNORE_SUBQUERIES);
          return (Node *) newnode;
      }
      else
--- 771,787 ----
          Query       *newnode;

          FLATCOPY(newnode, query, Query);
          query_tree_mutator(newnode, adjust_inherited_attrs_mutator,
                             (void *) &context, QTW_IGNORE_SUBQUERIES);
+         if (newnode->resultRelation == old_rt_index)
+         {
+             newnode->resultRelation = new_rt_index;
+             /* Fix tlist resnos too, if it's inherited UPDATE */
+             if (newnode->commandType == CMD_UPDATE)
+                 newnode->targetList =
+                     adjust_inherited_tlist(newnode->targetList,
+                                            new_relid);
+         }
          return (Node *) newnode;
      }
      else
***************
*** 888,891 ****
--- 896,997 ----

      return expression_tree_mutator(node, adjust_inherited_attrs_mutator,
                                     (void *) context);
+ }
+
+ /*
+  * Adjust the targetlist entries of an inherited UPDATE operation
+  *
+  * The expressions have already been fixed, but we have to make sure that
+  * the target resnos match the child table (they may not, in the case of
+  * a column that was added after-the-fact by ALTER TABLE).  In some cases
+  * this can force us to re-order the tlist to preserve resno ordering.
+  * (We do all this work in special cases so that preptlist.c is fast for
+  * the typical case.)
+  *
+  * The given tlist has already been through expression_tree_mutator;
+  * therefore the TargetEntry nodes are fresh copies that it's okay to
+  * scribble on.  But the Resdom nodes have not been copied; make new ones
+  * if we need to change them!
+  *
+  * Note that this is not needed for INSERT because INSERT isn't inheritable.
+  */
+ static List *
+ adjust_inherited_tlist(List *tlist, Oid new_relid)
+ {
+     bool        changed_it = false;
+     List       *tl;
+     List       *new_tlist;
+     bool        more;
+     int            attrno;
+
+     /* Scan tlist and update resnos to match attnums of new_relid */
+     foreach(tl, tlist)
+     {
+         TargetEntry *tle = (TargetEntry *) lfirst(tl);
+         Resdom       *resdom = tle->resdom;
+
+         if (resdom->resjunk)
+             continue;            /* ignore junk items */
+
+         attrno = get_attnum(new_relid, resdom->resname);
+         if (attrno == InvalidAttrNumber)
+             elog(ERROR, "Relation \"%s\" has no column \"%s\"",
+                  get_rel_name(new_relid), resdom->resname);
+         if (resdom->resno != attrno)
+         {
+             resdom = (Resdom *) copyObject((Node *) resdom);
+             resdom->resno = attrno;
+             tle->resdom = resdom;
+             changed_it = true;
+         }
+     }
+
+     /*
+      * If we changed anything, re-sort the tlist by resno, and make sure
+      * resjunk entries have resnos above the last real resno.  The sort
+      * algorithm is a bit stupid, but for such a seldom-taken path, small
+      * is probably better than fast.
+      */
+     if (!changed_it)
+         return tlist;
+
+     new_tlist = NIL;
+     more = true;
+     for (attrno = 1; more; attrno++)
+     {
+         more = false;
+         foreach(tl, tlist)
+         {
+             TargetEntry *tle = (TargetEntry *) lfirst(tl);
+             Resdom       *resdom = tle->resdom;
+
+             if (resdom->resjunk)
+                 continue;        /* ignore junk items */
+
+             if (resdom->resno == attrno)
+                 new_tlist = lappend(new_tlist, tle);
+             else if (resdom->resno > attrno)
+                 more = true;
+         }
+     }
+
+     foreach(tl, tlist)
+     {
+         TargetEntry *tle = (TargetEntry *) lfirst(tl);
+         Resdom       *resdom = tle->resdom;
+
+         if (!resdom->resjunk)
+             continue;            /* here, ignore non-junk items */
+
+         if (resdom->resno != attrno)
+         {
+             resdom = (Resdom *) copyObject((Node *) resdom);
+             resdom->resno = attrno;
+             tle->resdom = resdom;
+         }
+         new_tlist = lappend(new_tlist, tle);
+         attrno++;
+     }
+
+     return new_tlist;
  }

pgsql-bugs by date:

Previous
From: Tom Lane
Date:
Subject: Re: Bug #863: pg_dump segfaults
Next
From: Ruslan A Dautkhanov
Date:
Subject: Serialize transactions