Clarify error message and documentation related to typed tables.

We restrict typed tables (those declared as "OF composite_type")
to be based on stand-alone composite types, not composite types
that are the implicitly-created rowtypes of other tables.
But if you tried to do that, you got the very confusing error
message "type foo is not a composite type".  Provide a more specific
message for that case.  Also clarify related documentation in the
CREATE TABLE man page.

Erik Wienhold and David G. Johnston, per complaint from Hannu Krosing.

Discussion: https://postgr.es/m/CAMT0RQRysCb_Amy5CTENSc5GfsvXL1a4qX3mv_hx31_v74P==g@mail.gmail.com
This commit is contained in:
Tom Lane 2024-07-26 12:39:45 -04:00
parent c883453cb2
commit 5d1d8b3c82
4 changed files with 26 additions and 10 deletions

View File

@ -249,18 +249,18 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
<listitem> <listitem>
<para> <para>
Creates a <firstterm>typed table</firstterm>, which takes its Creates a <firstterm>typed table</firstterm>, which takes its
structure from the specified composite type (name optionally structure from the specified stand-alone composite type (that is,
schema-qualified). A typed table is tied to its type; for one created using <xref linkend="sql-createtype"/>) though it still
example the table will be dropped if the type is dropped produces a new composite type as well. The table will have a
(with <literal>DROP TYPE ... CASCADE</literal>). dependency on the referenced type, meaning that cascaded alter and
drop actions on that type will propagate to the table.
</para> </para>
<para> <para>
When a typed table is created, then the data types of the A typed table always has the same column names and data types as the
columns are determined by the underlying composite type and are type it is derived from, so you cannot specify additional columns.
not specified by the <literal>CREATE TABLE</literal> command.
But the <literal>CREATE TABLE</literal> command can add defaults But the <literal>CREATE TABLE</literal> 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.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -6962,8 +6962,15 @@ check_of_type(HeapTuple typetuple)
* the type before the typed table creation/conversion commits. * the type before the typed table creation/conversion commits.
*/ */
relation_close(typeRelation, NoLock); relation_close(typeRelation, NoLock);
if (!typeOk)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("type %s is the row type of another table",
format_type_be(typ->oid)),
errdetail("A typed table must use a stand-alone composite type created with CREATE TYPE.")));
} }
if (!typeOk) else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE), (errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("type %s is not a composite type", errmsg("type %s is not a composite type",

View File

@ -89,7 +89,12 @@ drop cascades to function get_all_persons()
drop cascades to table persons2 drop cascades to table persons2
drop cascades to table persons3 drop cascades to table persons3
CREATE TABLE persons5 OF stuff; -- only CREATE TYPE AS types may be used CREATE TABLE persons5 OF stuff; -- only CREATE TYPE AS types may be used
ERROR: type stuff is not a composite type ERROR: type stuff is the row type of another table
DETAIL: A typed table must use a stand-alone composite type created with CREATE TYPE.
CREATE TYPE tt_enum_type AS ENUM ('a');
CREATE TABLE of_tt_enum_type OF tt_enum_type; -- not a composite type at all
ERROR: type tt_enum_type is not a composite type
DROP TYPE tt_enum_type;
DROP TABLE stuff; DROP TABLE stuff;
-- implicit casting -- implicit casting
CREATE TYPE person_type AS (id int, name text); CREATE TYPE person_type AS (id int, name text);

View File

@ -48,6 +48,10 @@ DROP TYPE person_type CASCADE;
CREATE TABLE persons5 OF stuff; -- only CREATE TYPE AS types may be used CREATE TABLE persons5 OF stuff; -- only CREATE TYPE AS types may be used
CREATE TYPE tt_enum_type AS ENUM ('a');
CREATE TABLE of_tt_enum_type OF tt_enum_type; -- not a composite type at all
DROP TYPE tt_enum_type;
DROP TABLE stuff; DROP TABLE stuff;