index a090981e5c4161ff7dd72690e8f26e87135edbd0..d74700f716f81800149af4073c526e967bd242c9 100644 (file)
@@ -422,6 +422,7 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
{
CheckAttributeType(NameStr(tupdesc->attrs[i]->attname),
tupdesc->attrs[i]->atttypid,
+ NIL, /* assume we're creating a new rowtype */
allow_system_table_mods);
}
}
@@ -430,15 +431,24 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
* CheckAttributeType
*
* Verify that the proposed datatype of an attribute is legal.
- * This is needed because there are types (and pseudo-types)
+ * This is needed mainly because there are types (and pseudo-types)
* in the catalogs that we do not support as elements of real tuples.
+ * We also check some other properties required of a table column.
+ *
+ * If the attribute is being proposed for addition to an existing table or
+ * composite type, pass a one-element list of the rowtype OID as
+ * containing_rowtypes. When checking a to-be-created rowtype, it's
+ * sufficient to pass NIL, because there could not be any recursive reference
+ * to a not-yet-existing rowtype.
* --------------------------------
*/
void
CheckAttributeType(const char *attname, Oid atttypid,
+ List *containing_rowtypes,
bool allow_system_table_mods)
{
char att_typtype = get_typtype(atttypid);
+ Oid att_typelem;
if (atttypid == UNKNOWNOID)
{
@@ -476,6 +486,20 @@ CheckAttributeType(const char *attname, Oid atttypid,
TupleDesc tupdesc;
int i;
+ /*
+ * Check for self-containment. Eventually we might be able to allow
+ * this (just return without complaint, if so) but it's not clear how
+ * many other places would require anti-recursion defenses before it
+ * would be safe to allow tables to contain their own rowtype.
+ */
+ if (list_member_oid(containing_rowtypes, atttypid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ errmsg("composite type %s cannot be made a member of itself",
+ format_type_be(atttypid))));
+
+ containing_rowtypes = lcons_oid(atttypid, containing_rowtypes);
+
relation = relation_open(get_typ_typrelid(atttypid), AccessShareLock);
tupdesc = RelationGetDescr(relation);
@@ -487,10 +511,22 @@ CheckAttributeType(const char *attname, Oid atttypid,
if (attr->attisdropped)
continue;
CheckAttributeType(NameStr(attr->attname), attr->atttypid,
+ containing_rowtypes,
allow_system_table_mods);
}
relation_close(relation, AccessShareLock);
+
+ containing_rowtypes = list_delete_first(containing_rowtypes);
+ }
+ else if (OidIsValid((att_typelem = get_element_type(atttypid))))
+ {
+ /*
+ * Must recurse into array types, too, in case they are composite.
+ */
+ CheckAttributeType(attname, att_typelem,
+ containing_rowtypes,
+ allow_system_table_mods);
}
}
index 6a1804b6fec7173b722836be0d3092bc3679a6e5..64141c03408d6324da1e85337bc5b01c8c70fe74 100644 (file)
@@ -3729,7 +3729,9 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
typeOid = HeapTupleGetOid(typeTuple);
/* make sure datatype is legal for a column */
- CheckAttributeType(colDef->colname, typeOid, false);
+ CheckAttributeType(colDef->colname, typeOid,
+ list_make1_oid(rel->rd_rel->reltype),
+ false);
/* construct new attribute's pg_attribute entry */
attribute.attrelid = myrelid;
targettype = typenameTypeId(NULL, typeName, &targettypmod);
/* make sure datatype is legal for a column */
- CheckAttributeType(colName, targettype, false);
+ CheckAttributeType(colName, targettype,
+ list_make1_oid(rel->rd_rel->reltype),
+ false);
/*
* Set up an expression to transform the old data value to the new type.
index 40a907d869e90225dc841257e4f7a2879afc2c9f..a460371a112412c70bdf578b27f40adc45b164c1 100644 (file)
(3 rows)
drop table another;
+-- disallow recursive containment of row types
+create temp table recur1 (f1 int);
+alter table recur1 add column f2 recur1; -- fails
+ERROR: composite type recur1 cannot be made a member of itself
+alter table recur1 add column f2 recur1[]; -- fails
+ERROR: composite type recur1 cannot be made a member of itself
+create temp table recur2 (f1 int, f2 recur1);
+alter table recur1 add column f2 recur2; -- fails
+ERROR: composite type recur1 cannot be made a member of itself
+alter table recur1 add column f2 int;
+alter table recur1 alter column f2 type recur2; -- fails
+ERROR: composite type recur1 cannot be made a member of itself
--
-- alter function
--