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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers