Tom Lane wrote:

> We could probably fix the specific issue being seen here by passing the
> expression tree through a suitable attno remapping,

Here's a first attempt at fixing this.  It makes the test pass, but I
have the feeling that more complex ones might need more work.  Have to
leave for a bit now.

-- 
Álvaro Herrera                https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e70d752..75fd45a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -7999,12 +7999,96 @@ ATPrepAlterColumnType(List **wqueue,
        ReleaseSysCache(tuple);
 
        /*
-        * The recursion case is handled by ATSimpleRecursion.  However, if we 
are
-        * told not to recurse, there had better not be any child tables; else 
the
-        * alter would put them out of step.
+        * Recurse manually, if necessary.  We cannot apply ATSimpleRecursion 
here
+        * because we need to remap attribute numbers for each child.
+        *
+        * If we are told not to recurse, there had better not be any child
+        * tables; else the alter would put them out of step.
         */
        if (recurse)
-               ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
+       {
+               Oid                     relid = RelationGetRelid(rel);
+               ListCell   *child;
+               List       *children;
+
+               children = find_all_inheritors(relid, lockmode, NULL);
+
+               /*
+                * find_all_inheritors does the recursive search of the 
inheritance
+                * hierarchy, so all we have to do is process all of the relids 
in the
+                * list that it returns.
+                */
+               foreach(child, children)
+               {
+                       Oid                     childrelid = lfirst_oid(child);
+                       Relation        childrel;
+                       AttrNumber *attmap;
+                       AttrNumber      parent_attno;
+                       bool            found_whole_row;
+                       TupleDesc       parentDesc;
+                       TupleDesc       childDesc;
+
+                       if (childrelid == relid)
+                               continue;
+
+                       /* find_all_inheritors already got lock */
+                       childrel = relation_open(childrelid, NoLock);
+                       CheckTableNotInUse(childrel, "ALTER TABLE");
+
+                       /*
+                        * Build an attribute map for map_variable_attnos.  
This is O(N^2)
+                        * on the number of attributes ...
+                        */
+                       parentDesc = RelationGetDescr(rel);
+                       childDesc = RelationGetDescr(childrel);
+                       attmap = (AttrNumber *) palloc0(sizeof(AttrNumber) *
+                                                                               
        parentDesc->natts);
+                       for (parent_attno = 1;
+                                parent_attno <= parentDesc->natts;
+                                parent_attno++)
+                       {
+                               bool    found = false;
+                               AttrNumber child_attno;
+
+                               for (child_attno = 1;
+                                        child_attno <= childDesc->natts;
+                                        child_attno++)
+                               {
+                                       if 
(strncmp(NameStr(parentDesc->attrs[parent_attno - 1]->attname),
+                                                               
NameStr(childDesc->attrs[child_attno - 1]->attname),
+                                                               NAMEDATALEN) == 
0)
+                                       {
+                                               attmap[parent_attno - 1] = 
child_attno;
+                                               found = true;
+                                               break;
+                                       }
+                               }
+
+                               /* should not happen */
+                               if (!found)
+                                       elog(ERROR, "column \"%s\" not found in 
child table \"%s\"",
+                                                
NameStr(parentDesc->attrs[parent_attno - 1]->attname),
+                                                
RelationGetRelationName(childrel));
+                       }
+
+                       /*
+                        * Queue a command for this child, with remapped 
attnums.  Note
+                        * that ATPrepCmd creates a copy, so there's no need to 
do that
+                        * here.  XXX what about the entry for the parent table?
+                        */
+                       def->cooked_default =
+                               map_variable_attnos(transform,
+                                                                       1, 0,
+                                                                       attmap, 
parentDesc->natts,
+                                                                       
&found_whole_row);
+                       if (found_whole_row)
+                               elog(ERROR, "unexpected whole-row reference");
+                       ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode);
+                       relation_close(childrel, NoLock);
+
+                       pfree(attmap);
+               }
+       }
        else if (!recursing &&
                         find_inheritance_children(RelationGetRelid(rel), 
NoLock) != NIL)
                ereport(ERROR,
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to