summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/heap.c43
-rw-r--r--src/backend/commands/tablecmds.c6
-rw-r--r--src/include/catalog/heap.h3
-rw-r--r--src/test/regress/expected/alter_table.out12
-rw-r--r--src/test/regress/sql/alter_table.sql9
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
--