diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/catalog/heap.c | 43 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 6 | ||||
-rw-r--r-- | src/include/catalog/heap.h | 3 | ||||
-rw-r--r-- | src/test/regress/expected/alter_table.out | 12 | ||||
-rw-r--r-- | src/test/regress/sql/alter_table.sql | 9 |
5 files changed, 66 insertions, 7 deletions
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 9efef447785..edc5427341a 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -388,7 +388,8 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind) for (i = 0; i < natts; i++) { CheckAttributeType(NameStr(tupdesc->attrs[i]->attname), - tupdesc->attrs[i]->atttypid); + tupdesc->attrs[i]->atttypid, + NIL /* assume we're creating a new rowtype */); } } @@ -396,14 +397,23 @@ 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) +CheckAttributeType(const char *attname, Oid atttypid, + List *containing_rowtypes) { char att_typtype = get_typtype(atttypid); + Oid att_typelem; if (atttypid == UNKNOWNOID) { @@ -439,6 +449,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); @@ -449,10 +473,21 @@ CheckAttributeType(const char *attname, Oid atttypid) if (attr->attisdropped) continue; - CheckAttributeType(NameStr(attr->attname), attr->atttypid); + CheckAttributeType(NameStr(attr->attname), attr->atttypid, + containing_rowtypes); } 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); } } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 14757befdff..4e3e04d077b 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -3119,7 +3119,8 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel, typeOid = HeapTupleGetOid(typeTuple); /* make sure datatype is legal for a column */ - CheckAttributeType(colDef->colname, typeOid); + CheckAttributeType(colDef->colname, typeOid, + list_make1_oid(rel->rd_rel->reltype)); attributeTuple = heap_addheader(Natts_pg_attribute, false, @@ -4818,7 +4819,8 @@ ATPrepAlterColumnType(List **wqueue, targettype = typenameTypeId(NULL, typename, &targettypmod); /* make sure datatype is legal for a column */ - CheckAttributeType(colName, targettype); + CheckAttributeType(colName, targettype, + list_make1_oid(rel->rd_rel->reltype)); /* * Set up an expression to transform the old data value to the new type. diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index 727af295c76..678c11e7f6e 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -98,6 +98,7 @@ extern Form_pg_attribute SystemAttributeByName(const char *attname, extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind); -extern void CheckAttributeType(const char *attname, Oid atttypid); +extern void CheckAttributeType(const char *attname, Oid atttypid, + List *containing_rowtypes); #endif /* HEAP_H */ diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 51d5afa81fd..a6e4eeaaa3b 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -1384,6 +1384,18 @@ select * from another; (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 -- diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 81cc70612d5..c6ce7ae4db7 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -1045,6 +1045,15 @@ select * from another; drop table another; +-- disallow recursive containment of row types +create temp table recur1 (f1 int); +alter table recur1 add column f2 recur1; -- fails +alter table recur1 add column f2 recur1[]; -- fails +create temp table recur2 (f1 int, f2 recur1); +alter table recur1 add column f2 recur2; -- fails +alter table recur1 add column f2 int; +alter table recur1 alter column f2 type recur2; -- fails + -- -- alter function -- |