Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/common/tupconvert.c110
-rw-r--r--src/backend/commands/tablecmds.c66
2 files changed, 127 insertions, 49 deletions
diff --git a/src/backend/access/common/tupconvert.c b/src/backend/access/common/tupconvert.c
index 3752abbde72..b17ceafa6ef 100644
--- a/src/backend/access/common/tupconvert.c
+++ b/src/backend/access/common/tupconvert.c
@@ -206,55 +206,12 @@ convert_tuples_by_name(TupleDesc indesc,
{
TupleConversionMap *map;
AttrNumber *attrMap;
- int n;
+ int n = outdesc->natts;
int i;
bool same;
/* Verify compatibility and prepare attribute-number map */
- n = outdesc->natts;
- attrMap = (AttrNumber *) palloc0(n * sizeof(AttrNumber));
- for (i = 0; i < n; i++)
- {
- Form_pg_attribute att = outdesc->attrs[i];
- char *attname;
- Oid atttypid;
- int32 atttypmod;
- int j;
-
- if (att->attisdropped)
- continue; /* attrMap[i] is already 0 */
- attname = NameStr(att->attname);
- atttypid = att->atttypid;
- atttypmod = att->atttypmod;
- for (j = 0; j < indesc->natts; j++)
- {
- att = indesc->attrs[j];
- if (att->attisdropped)
- continue;
- if (strcmp(attname, NameStr(att->attname)) == 0)
- {
- /* Found it, check type */
- if (atttypid != att->atttypid || atttypmod != att->atttypmod)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg_internal("%s", _(msg)),
- errdetail("Attribute \"%s\" of type %s does not match corresponding attribute of type %s.",
- attname,
- format_type_be(outdesc->tdtypeid),
- format_type_be(indesc->tdtypeid))));
- attrMap[i] = (AttrNumber) (j + 1);
- break;
- }
- }
- if (attrMap[i] == 0)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg_internal("%s", _(msg)),
- errdetail("Attribute \"%s\" of type %s does not exist in type %s.",
- attname,
- format_type_be(outdesc->tdtypeid),
- format_type_be(indesc->tdtypeid))));
- }
+ attrMap = convert_tuples_by_name_map(indesc, outdesc, msg);
/*
* Check to see if the map is one-to-one and the tuple types are the same.
@@ -313,6 +270,69 @@ convert_tuples_by_name(TupleDesc indesc,
}
/*
+ * Return a palloc'd bare attribute map for tuple conversion, matching input
+ * and output columns by name. (Dropped columns are ignored in both input and
+ * output.) This is normally a subroutine for convert_tuples_by_name, but can
+ * be used standalone.
+ */
+AttrNumber *
+convert_tuples_by_name_map(TupleDesc indesc,
+ TupleDesc outdesc,
+ const char *msg)
+{
+ AttrNumber *attrMap;
+ int n;
+ int i;
+
+ n = outdesc->natts;
+ attrMap = (AttrNumber *) palloc0(n * sizeof(AttrNumber));
+ for (i = 0; i < n; i++)
+ {
+ Form_pg_attribute att = outdesc->attrs[i];
+ char *attname;
+ Oid atttypid;
+ int32 atttypmod;
+ int j;
+
+ if (att->attisdropped)
+ continue; /* attrMap[i] is already 0 */
+ attname = NameStr(att->attname);
+ atttypid = att->atttypid;
+ atttypmod = att->atttypmod;
+ for (j = 0; j < indesc->natts; j++)
+ {
+ att = indesc->attrs[j];
+ if (att->attisdropped)
+ continue;
+ if (strcmp(attname, NameStr(att->attname)) == 0)
+ {
+ /* Found it, check type */
+ if (atttypid != att->atttypid || atttypmod != att->atttypmod)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg_internal("%s", _(msg)),
+ errdetail("Attribute \"%s\" of type %s does not match corresponding attribute of type %s.",
+ attname,
+ format_type_be(outdesc->tdtypeid),
+ format_type_be(indesc->tdtypeid))));
+ attrMap[i] = (AttrNumber) (j + 1);
+ break;
+ }
+ }
+ if (attrMap[i] == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg_internal("%s", _(msg)),
+ errdetail("Attribute \"%s\" of type %s does not exist in type %s.",
+ attname,
+ format_type_be(outdesc->tdtypeid),
+ format_type_be(indesc->tdtypeid))));
+ }
+
+ return attrMap;
+}
+
+/*
* Perform conversion of a tuple according to the map.
*/
HeapTuple
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index cffe2751790..42558ec42e0 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -20,6 +20,7 @@
#include "access/reloptions.h"
#include "access/relscan.h"
#include "access/sysattr.h"
+#include "access/tupconvert.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
@@ -8540,12 +8541,69 @@ 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 by queueing a new command for each child, if
+ * necessary. We cannot apply ATSimpleRecursion here because we need to
+ * remap attribute numbers in the USING expression, if any.
+ *
+ * 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;
+
+ if (childrelid == relid)
+ continue;
+
+ /* find_all_inheritors already got lock */
+ childrel = relation_open(childrelid, NoLock);
+ CheckTableNotInUse(childrel, "ALTER TABLE");
+
+ /*
+ * Remap the attribute numbers. If no USING expression was
+ * specified, there is no need for this step.
+ */
+ if (def->cooked_default)
+ {
+ AttrNumber *attmap;
+ bool found_whole_row;
+
+ /* create a copy to scribble on */
+ cmd = copyObject(cmd);
+
+ attmap = convert_tuples_by_name_map(RelationGetDescr(childrel),
+ RelationGetDescr(rel),
+ gettext_noop("could not convert row type"));
+ ((ColumnDef *) cmd->def)->cooked_default =
+ map_variable_attnos(def->cooked_default,
+ 1, 0,
+ attmap, RelationGetDescr(rel)->natts,
+ &found_whole_row);
+ if (found_whole_row)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot convert whole-row table reference"),
+ errdetail("USING expression contains a whole-row table reference.")));
+ pfree(attmap);
+ }
+ ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode);
+ relation_close(childrel, NoLock);
+ }
+ }
else if (!recursing &&
find_inheritance_children(RelationGetRelid(rel), NoLock) != NIL)
ereport(ERROR,