From 04db0fdbfa9382730bb65f94bca2cd8063a3456a Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Mon, 18 Apr 2011 10:13:34 -0400 Subject: [PATCH] Only allow typed tables to hang off composite types, not e.g. tables. This also ensures that we take a relation lock on the composite type when creating a typed table, which is necessary to prevent the composite type and the typed table from getting out of step in the face of concurrent DDL. Noah Misch, with some changes. --- src/backend/parser/parse_utilcmd.c | 17 ++++++++++++++++- src/test/regress/expected/typed_table.out | 2 ++ src/test/regress/sql/typed_table.sql | 2 ++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index eba890bf88..4f1bb34dae 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -825,6 +825,7 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename) TupleDesc tupdesc; int i; Oid ofTypeId; + bool typeOk = false; AssertArg(ofTypename); @@ -833,7 +834,21 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename) ofTypeId = HeapTupleGetOid(tuple); ofTypename->typeOid = ofTypeId; /* cached for later */ - if (typ->typtype != TYPTYPE_COMPOSITE) + if (typ->typtype == TYPTYPE_COMPOSITE) + { + Relation typeRelation; + + Assert(OidIsValid(typ->typrelid)); + typeRelation = relation_open(typ->typrelid, AccessShareLock); + typeOk = (typeRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE); + /* + * Close the parent rel, but keep our AccessShareLock on it until xact + * commit. That will prevent someone else from deleting or ALTERing + * the type before the typed table creation commits. + */ + relation_close(typeRelation, NoLock); + } + if (!typeOk) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("type %s is not a composite type", diff --git a/src/test/regress/expected/typed_table.out b/src/test/regress/expected/typed_table.out index 0874a64d55..1fe426d6e3 100644 --- a/src/test/regress/expected/typed_table.out +++ b/src/test/regress/expected/typed_table.out @@ -91,6 +91,8 @@ DETAIL: drop cascades to table persons drop cascades to function get_all_persons() drop cascades to table persons2 drop cascades to table persons3 +CREATE TABLE persons5 OF stuff; -- only CREATE TYPE AS types may be used +ERROR: type stuff is not a composite type DROP TABLE stuff; -- implicit casting CREATE TYPE person_type AS (id int, name text); diff --git a/src/test/regress/sql/typed_table.sql b/src/test/regress/sql/typed_table.sql index b0d452c387..25aaccb8bc 100644 --- a/src/test/regress/sql/typed_table.sql +++ b/src/test/regress/sql/typed_table.sql @@ -46,6 +46,8 @@ CREATE TABLE persons4 OF person_type ( DROP TYPE person_type RESTRICT; DROP TYPE person_type CASCADE; +CREATE TABLE persons5 OF stuff; -- only CREATE TYPE AS types may be used + DROP TABLE stuff;