aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/heap.c38
-rw-r--r--src/backend/catalog/index.c3
-rw-r--r--src/backend/commands/tablecmds.c8
-rw-r--r--src/include/catalog/heap.h1
-rw-r--r--src/test/regress/expected/alter_table.out12
-rw-r--r--src/test/regress/sql/alter_table.sql9
6 files changed, 67 insertions, 4 deletions
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index a090981e5c4..d74700f716f 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -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);
}
}
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 54cf280d57f..caa985a791f 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -258,7 +258,8 @@ ConstructTupleDescriptor(Relation heapRelation,
* whether a table column is of a safe type (which is why we
* needn't check for the non-expression case).
*/
- CheckAttributeType(NameStr(to->attname), to->atttypid, false);
+ CheckAttributeType(NameStr(to->attname), to->atttypid,
+ NIL, false);
}
/*
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 6a1804b6fec..64141c03408 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -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;
@@ -5858,7 +5860,9 @@ ATPrepAlterColumnType(List **wqueue,
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.
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index 557c311bc22..6a91ddb4fc3 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -115,6 +115,7 @@ extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
bool allow_system_table_mods);
extern void CheckAttributeType(const char *attname, Oid atttypid,
+ List *containing_rowtypes,
bool allow_system_table_mods);
#endif /* HEAP_H */
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 40a907d869e..a460371a112 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -1476,6 +1476,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 2b01238e282..8f472cff1e5 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -1092,6 +1092,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
--