From 39d2dc9b58dfa3b68245070648ecdf9eed892c7a Mon Sep 17 00:00:00 2001 From: Erik Wienhold Date: Fri, 8 Mar 2024 04:21:56 +0100 Subject: [PATCH v6] Document that typed tables rely on CREATE TYPE CREATE TABLE OF requires a stand-alone composite type that is not the row type of another table. Clarify that with a reference to CREATE TYPE in the docs. Also report a separate error message in this case. Reworded docs provided by David G. Johnston. --- doc/src/sgml/ref/create_table.sgml | 16 ++++++++-------- src/backend/commands/tablecmds.c | 9 ++++++++- src/test/regress/expected/typed_table.out | 7 ++++++- src/test/regress/sql/typed_table.sql | 4 ++++ 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index f19306e776..11458be9cf 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -249,18 +249,18 @@ WITH ( MODULUS numeric_literal, REM Creates a typed table, which takes its - structure from the specified composite type (name optionally - schema-qualified). A typed table is tied to its type; for - example the table will be dropped if the type is dropped - (with DROP TYPE ... CASCADE). + structure from an existing (name optionally schema-qualified) stand-alone + composite type (i.e., created using ) + though it still produces a new composite type as well. The table will + have a dependency on the referenced type such that cascaded alter and + drop actions on the type will propagate to the table. - When a typed table is created, then the data types of the - columns are determined by the underlying composite type and are - not specified by the CREATE TABLE command. + A typed table always has the same column names and data types as the + type it is derived from, and you cannot specify additional columns. But the CREATE TABLE command can add defaults - and constraints to the table and can specify storage parameters. + and constraints to the table, as well as specify storage parameters. diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 313c782cae..2331a9185a 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -6935,8 +6935,15 @@ check_of_type(HeapTuple typetuple) * the type before the typed table creation/conversion commits. */ relation_close(typeRelation, NoLock); + + if (!typeOk) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("type %s must not be a row type of another table", + format_type_be(typ->oid)), + errhint("Must be a stand-alone composite type created with CREATE TYPE."))); } - if (!typeOk) + else 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 2e47ecbcf5..5743e74978 100644 --- a/src/test/regress/expected/typed_table.out +++ b/src/test/regress/expected/typed_table.out @@ -89,8 +89,13 @@ 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 +ERROR: type stuff must not be a row type of another table +HINT: Must be a stand-alone composite type created with CREATE TYPE. DROP TABLE stuff; +CREATE TYPE simple AS ENUM ('a'); +CREATE TABLE of_simple OF simple; -- not a composite type +ERROR: type simple is not a composite type +DROP TYPE simple; -- implicit casting CREATE TYPE person_type AS (id int, name text); CREATE TABLE persons OF person_type; diff --git a/src/test/regress/sql/typed_table.sql b/src/test/regress/sql/typed_table.sql index 9ef0cdfcc7..d9b9398857 100644 --- a/src/test/regress/sql/typed_table.sql +++ b/src/test/regress/sql/typed_table.sql @@ -50,6 +50,10 @@ CREATE TABLE persons5 OF stuff; -- only CREATE TYPE AS types may be used DROP TABLE stuff; +CREATE TYPE simple AS ENUM ('a'); +CREATE TABLE of_simple OF simple; -- not a composite type +DROP TYPE simple; + -- implicit casting -- 2.45.1