|
14 | 14 | *
|
15 | 15 | *
|
16 | 16 | * IDENTIFICATION
|
17 |
| - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.83 2002/12/14 00:17:57 tgl Exp $ |
| 17 | + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.84 2003/01/05 00:56:40 tgl Exp $ |
18 | 18 | *
|
19 | 19 | *-------------------------------------------------------------------------
|
20 | 20 | */
|
@@ -67,6 +67,7 @@ static List *generate_append_tlist(List *colTypes, bool flag,
|
67 | 67 | List *refnames_tlist);
|
68 | 68 | static Node *adjust_inherited_attrs_mutator(Node *node,
|
69 | 69 | adjust_inherited_attrs_context *context);
|
| 70 | +static List *adjust_inherited_tlist(List *tlist, Oid new_relid); |
70 | 71 |
|
71 | 72 |
|
72 | 73 | /*
|
@@ -768,10 +769,17 @@ adjust_inherited_attrs(Node *node,
|
768 | 769 | Query *newnode;
|
769 | 770 |
|
770 | 771 | FLATCOPY(newnode, query, Query);
|
771 |
| - if (newnode->resultRelation == old_rt_index) |
772 |
| - newnode->resultRelation = new_rt_index; |
773 | 772 | query_tree_mutator(newnode, adjust_inherited_attrs_mutator,
|
774 | 773 | (void *) &context, QTW_IGNORE_SUBQUERIES);
|
| 774 | + if (newnode->resultRelation == old_rt_index) |
| 775 | + { |
| 776 | + newnode->resultRelation = new_rt_index; |
| 777 | + /* Fix tlist resnos too, if it's inherited UPDATE */ |
| 778 | + if (newnode->commandType == CMD_UPDATE) |
| 779 | + newnode->targetList = |
| 780 | + adjust_inherited_tlist(newnode->targetList, |
| 781 | + new_relid); |
| 782 | + } |
775 | 783 | return (Node *) newnode;
|
776 | 784 | }
|
777 | 785 | else
|
@@ -887,3 +895,101 @@ adjust_inherited_attrs_mutator(Node *node,
|
887 | 895 | return expression_tree_mutator(node, adjust_inherited_attrs_mutator,
|
888 | 896 | (void *) context);
|
889 | 897 | }
|
| 898 | + |
| 899 | +/* |
| 900 | + * Adjust the targetlist entries of an inherited UPDATE operation |
| 901 | + * |
| 902 | + * The expressions have already been fixed, but we have to make sure that |
| 903 | + * the target resnos match the child table (they may not, in the case of |
| 904 | + * a column that was added after-the-fact by ALTER TABLE). In some cases |
| 905 | + * this can force us to re-order the tlist to preserve resno ordering. |
| 906 | + * (We do all this work in special cases so that preptlist.c is fast for |
| 907 | + * the typical case.) |
| 908 | + * |
| 909 | + * The given tlist has already been through expression_tree_mutator; |
| 910 | + * therefore the TargetEntry nodes are fresh copies that it's okay to |
| 911 | + * scribble on. But the Resdom nodes have not been copied; make new ones |
| 912 | + * if we need to change them! |
| 913 | + * |
| 914 | + * Note that this is not needed for INSERT because INSERT isn't inheritable. |
| 915 | + */ |
| 916 | +static List * |
| 917 | +adjust_inherited_tlist(List *tlist, Oid new_relid) |
| 918 | +{ |
| 919 | + bool changed_it = false; |
| 920 | + List *tl; |
| 921 | + List *new_tlist; |
| 922 | + bool more; |
| 923 | + int attrno; |
| 924 | + |
| 925 | + /* Scan tlist and update resnos to match attnums of new_relid */ |
| 926 | + foreach(tl, tlist) |
| 927 | + { |
| 928 | + TargetEntry *tle = (TargetEntry *) lfirst(tl); |
| 929 | + Resdom *resdom = tle->resdom; |
| 930 | + |
| 931 | + if (resdom->resjunk) |
| 932 | + continue; /* ignore junk items */ |
| 933 | + |
| 934 | + attrno = get_attnum(new_relid, resdom->resname); |
| 935 | + if (attrno == InvalidAttrNumber) |
| 936 | + elog(ERROR, "Relation \"%s\" has no column \"%s\"", |
| 937 | + get_rel_name(new_relid), resdom->resname); |
| 938 | + if (resdom->resno != attrno) |
| 939 | + { |
| 940 | + resdom = (Resdom *) copyObject((Node *) resdom); |
| 941 | + resdom->resno = attrno; |
| 942 | + tle->resdom = resdom; |
| 943 | + changed_it = true; |
| 944 | + } |
| 945 | + } |
| 946 | + |
| 947 | + /* |
| 948 | + * If we changed anything, re-sort the tlist by resno, and make sure |
| 949 | + * resjunk entries have resnos above the last real resno. The sort |
| 950 | + * algorithm is a bit stupid, but for such a seldom-taken path, small |
| 951 | + * is probably better than fast. |
| 952 | + */ |
| 953 | + if (!changed_it) |
| 954 | + return tlist; |
| 955 | + |
| 956 | + new_tlist = NIL; |
| 957 | + more = true; |
| 958 | + for (attrno = 1; more; attrno++) |
| 959 | + { |
| 960 | + more = false; |
| 961 | + foreach(tl, tlist) |
| 962 | + { |
| 963 | + TargetEntry *tle = (TargetEntry *) lfirst(tl); |
| 964 | + Resdom *resdom = tle->resdom; |
| 965 | + |
| 966 | + if (resdom->resjunk) |
| 967 | + continue; /* ignore junk items */ |
| 968 | + |
| 969 | + if (resdom->resno == attrno) |
| 970 | + new_tlist = lappend(new_tlist, tle); |
| 971 | + else if (resdom->resno > attrno) |
| 972 | + more = true; |
| 973 | + } |
| 974 | + } |
| 975 | + |
| 976 | + foreach(tl, tlist) |
| 977 | + { |
| 978 | + TargetEntry *tle = (TargetEntry *) lfirst(tl); |
| 979 | + Resdom *resdom = tle->resdom; |
| 980 | + |
| 981 | + if (!resdom->resjunk) |
| 982 | + continue; /* here, ignore non-junk items */ |
| 983 | + |
| 984 | + if (resdom->resno != attrno) |
| 985 | + { |
| 986 | + resdom = (Resdom *) copyObject((Node *) resdom); |
| 987 | + resdom->resno = attrno; |
| 988 | + tle->resdom = resdom; |
| 989 | + } |
| 990 | + new_tlist = lappend(new_tlist, tle); |
| 991 | + attrno++; |
| 992 | + } |
| 993 | + |
| 994 | + return new_tlist; |
| 995 | +} |
0 commit comments