CREATE TABLE ttable1 OF nothing;
ERROR:  type "nothing" does not exist
CREATE TYPE person_type AS (id int, name text);
CREATE TABLE persons OF person_type;
CREATE TABLE IF NOT EXISTS persons OF person_type;
NOTICE:  relation "persons" already exists, skipping
SELECT * FROM persons;
 id | name 
----+------
(0 rows)

\d persons
    Table "public.persons"
 Column |  Type   | Modifiers 
--------+---------+-----------
 id     | integer | 
 name   | text    | 
Typed table of type: person_type

CREATE FUNCTION get_all_persons() RETURNS SETOF person_type
LANGUAGE SQL
AS $$
    SELECT * FROM persons;
$$;
SELECT * FROM get_all_persons();
 id | name 
----+------
(0 rows)

-- certain ALTER TABLE operations on typed tables are not allowed
ALTER TABLE persons ADD COLUMN comment text;
ERROR:  cannot add column to typed table
ALTER TABLE persons DROP COLUMN name;
ERROR:  cannot drop column from typed table
ALTER TABLE persons RENAME COLUMN id TO num;
ERROR:  cannot rename column of typed table
ALTER TABLE persons ALTER COLUMN name TYPE varchar;
ERROR:  cannot alter column type of typed table
CREATE TABLE stuff (id int);
ALTER TABLE persons INHERIT stuff;
ERROR:  cannot change inheritance of typed table
CREATE TABLE personsx OF person_type (myname WITH OPTIONS NOT NULL); -- error
ERROR:  column "myname" does not exist
CREATE TABLE persons2 OF person_type (
    id WITH OPTIONS PRIMARY KEY,
    UNIQUE (name)
);
\d persons2
   Table "public.persons2"
 Column |  Type   | Modifiers 
--------+---------+-----------
 id     | integer | not null
 name   | text    | 
Indexes:
    "persons2_pkey" PRIMARY KEY, btree (id)
    "persons2_name_key" UNIQUE CONSTRAINT, btree (name)
Typed table of type: person_type

CREATE TABLE persons3 OF person_type (
    PRIMARY KEY (id),
    name WITH OPTIONS DEFAULT ''
);
\d persons3
       Table "public.persons3"
 Column |  Type   |    Modifiers     
--------+---------+------------------
 id     | integer | not null
 name   | text    | default ''::text
Indexes:
    "persons3_pkey" PRIMARY KEY, btree (id)
Typed table of type: person_type

CREATE TABLE persons4 OF person_type (
    name WITH OPTIONS NOT NULL,
    name WITH OPTIONS DEFAULT ''  -- error, specified more than once
);
ERROR:  column "name" specified more than once
DROP TYPE person_type RESTRICT;
ERROR:  cannot drop type person_type because other objects depend on it
DETAIL:  table persons depends on type person_type
function get_all_persons() depends on type person_type
table persons2 depends on type person_type
table persons3 depends on type person_type
HINT:  Use DROP ... CASCADE to drop the dependent objects too.
DROP TYPE person_type CASCADE;
NOTICE:  drop cascades to 4 other objects
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);
CREATE TABLE persons OF person_type;
INSERT INTO persons VALUES (1, 'test');
CREATE FUNCTION namelen(person_type) RETURNS int LANGUAGE SQL AS $$ SELECT length($1.name) $$;
SELECT id, namelen(persons) FROM persons;
 id | namelen 
----+---------
  1 |       4
(1 row)

DROP TYPE person_type CASCADE;
NOTICE:  drop cascades to 2 other objects
DETAIL:  drop cascades to table persons
drop cascades to function namelen(person_type)
