Commit 68739ba8 authored by Robert Haas's avatar Robert Haas

Allow ALTER TABLE name {OF type | NOT OF}.

This syntax allows a standalone table to be made into a typed table,
or a typed table to be made standalone.  This is possibly a mildly
useful feature in its own right, but the real motivation for this
change is that we need it to make pg_upgrade work with typed tables.
This doesn't actually fix that problem, but it's necessary
infrastructure.

Noah Misch
parent 520bcd9c
...@@ -63,6 +63,8 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable> ...@@ -63,6 +63,8 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
RESET ( <replaceable class="PARAMETER">storage_parameter</replaceable> [, ... ] ) RESET ( <replaceable class="PARAMETER">storage_parameter</replaceable> [, ... ] )
INHERIT <replaceable class="PARAMETER">parent_table</replaceable> INHERIT <replaceable class="PARAMETER">parent_table</replaceable>
NO INHERIT <replaceable class="PARAMETER">parent_table</replaceable> NO INHERIT <replaceable class="PARAMETER">parent_table</replaceable>
OF <replaceable class="PARAMETER">type_name</replaceable>
NOT OF
OWNER TO <replaceable class="PARAMETER">new_owner</replaceable> OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
SET TABLESPACE <replaceable class="PARAMETER">new_tablespace</replaceable> SET TABLESPACE <replaceable class="PARAMETER">new_tablespace</replaceable>
...@@ -490,6 +492,30 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable> ...@@ -490,6 +492,30 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><literal>OF <replaceable class="PARAMETER">type_name</replaceable></literal></term>
<listitem>
<para>
This form links the table to a composite type as though <command>CREATE
TABLE OF</> had formed it. The table's list of column names and types
must precisely match that of the composite type; the presence of
an <literal>oid</> system column is permitted to differ. The table must
not inherit from any other table. These restrictions ensure
that <command>CREATE TABLE OF</> would permit an equivalent table
definition.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>NOT OF</literal></term>
<listitem>
<para>
This form dissociates a typed table from its type.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><literal>OWNER</literal></term> <term><literal>OWNER</literal></term>
<listitem> <listitem>
......
This diff is collapsed.
...@@ -1933,6 +1933,23 @@ alter_table_cmd: ...@@ -1933,6 +1933,23 @@ alter_table_cmd:
n->def = (Node *) $3; n->def = (Node *) $3;
$$ = (Node *)n; $$ = (Node *)n;
} }
/* ALTER TABLE <name> OF <type_name> */
| OF any_name
{
AlterTableCmd *n = makeNode(AlterTableCmd);
TypeName *def = makeTypeNameFromNameList($2);
def->location = @2;
n->subtype = AT_AddOf;
n->def = (Node *) def;
$$ = (Node *)n;
}
/* ALTER TABLE <name> NOT OF */
| NOT OF
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_DropOf;
$$ = (Node *)n;
}
/* ALTER TABLE <name> OWNER TO RoleId */ /* ALTER TABLE <name> OWNER TO RoleId */
| OWNER TO RoleId | OWNER TO RoleId
{ {
......
...@@ -825,35 +825,15 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename) ...@@ -825,35 +825,15 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
TupleDesc tupdesc; TupleDesc tupdesc;
int i; int i;
Oid ofTypeId; Oid ofTypeId;
bool typeOk = false;
AssertArg(ofTypename); AssertArg(ofTypename);
tuple = typenameType(NULL, ofTypename, NULL); tuple = typenameType(NULL, ofTypename, NULL);
check_of_type(tuple);
typ = (Form_pg_type) GETSTRUCT(tuple); typ = (Form_pg_type) GETSTRUCT(tuple);
ofTypeId = HeapTupleGetOid(tuple); ofTypeId = HeapTupleGetOid(tuple);
ofTypename->typeOid = ofTypeId; /* cached for later */ ofTypename->typeOid = ofTypeId; /* cached for later */
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",
format_type_be(ofTypeId))));
tupdesc = lookup_rowtype_tupdesc(ofTypeId, -1); tupdesc = lookup_rowtype_tupdesc(ofTypeId, -1);
for (i = 0; i < tupdesc->natts; i++) for (i = 0; i < tupdesc->natts; i++)
{ {
......
...@@ -56,6 +56,8 @@ extern void find_composite_type_dependencies(Oid typeOid, ...@@ -56,6 +56,8 @@ extern void find_composite_type_dependencies(Oid typeOid,
Relation origRelation, Relation origRelation,
const char *origTypeName); const char *origTypeName);
extern void check_of_type(HeapTuple typetuple);
extern AttrNumber *varattnos_map(TupleDesc olddesc, TupleDesc newdesc); extern AttrNumber *varattnos_map(TupleDesc olddesc, TupleDesc newdesc);
extern AttrNumber *varattnos_map_schema(TupleDesc old, List *schema); extern AttrNumber *varattnos_map_schema(TupleDesc old, List *schema);
extern void change_varattnos_of_a_node(Node *node, const AttrNumber *newattno); extern void change_varattnos_of_a_node(Node *node, const AttrNumber *newattno);
......
...@@ -1219,6 +1219,8 @@ typedef enum AlterTableType ...@@ -1219,6 +1219,8 @@ typedef enum AlterTableType
AT_DisableRule, /* DISABLE RULE name */ AT_DisableRule, /* DISABLE RULE name */
AT_AddInherit, /* INHERIT parent */ AT_AddInherit, /* INHERIT parent */
AT_DropInherit, /* NO INHERIT parent */ AT_DropInherit, /* NO INHERIT parent */
AT_AddOf, /* OF <type_name> */
AT_DropOf, /* NOT OF */
AT_GenericOptions, /* OPTIONS (...) */ AT_GenericOptions, /* OPTIONS (...) */
} AlterTableType; } AlterTableType;
......
...@@ -1942,3 +1942,41 @@ Typed table of type: test_type2 ...@@ -1942,3 +1942,41 @@ Typed table of type: test_type2
CREATE TYPE test_type_empty AS (); CREATE TYPE test_type_empty AS ();
DROP TYPE test_type_empty; DROP TYPE test_type_empty;
--
-- typed tables: OF / NOT OF
--
CREATE TYPE tt_t0 AS (z inet, x int, y numeric(8,2));
ALTER TYPE tt_t0 DROP ATTRIBUTE z;
CREATE TABLE tt0 (x int NOT NULL, y numeric(8,2)); -- OK
CREATE TABLE tt1 (x int, y bigint); -- wrong base type
CREATE TABLE tt2 (x int, y numeric(9,2)); -- wrong typmod
CREATE TABLE tt3 (y numeric(8,2), x int); -- wrong column order
CREATE TABLE tt4 (x int); -- too few columns
CREATE TABLE tt5 (x int, y numeric(8,2), z int); -- too few columns
CREATE TABLE tt6 () INHERITS (tt0); -- can't have a parent
CREATE TABLE tt7 (x int, q text, y numeric(8,2)) WITH OIDS;
ALTER TABLE tt7 DROP q; -- OK
ALTER TABLE tt0 OF tt_t0;
ALTER TABLE tt1 OF tt_t0;
ERROR: table "tt1" has different type for column "y"
ALTER TABLE tt2 OF tt_t0;
ERROR: table "tt2" has different type for column "y"
ALTER TABLE tt3 OF tt_t0;
ERROR: table has column "y" where type requires "x"
ALTER TABLE tt4 OF tt_t0;
ERROR: table is missing column "y"
ALTER TABLE tt5 OF tt_t0;
ERROR: table has extra column "z"
ALTER TABLE tt6 OF tt_t0;
ERROR: typed tables cannot inherit
ALTER TABLE tt7 OF tt_t0;
CREATE TYPE tt_t1 AS (x int, y numeric(8,2));
ALTER TABLE tt7 OF tt_t1; -- reassign an already-typed table
ALTER TABLE tt7 NOT OF;
\d tt7
Table "public.tt7"
Column | Type | Modifiers
--------+--------------+-----------
x | integer |
y | numeric(8,2) |
...@@ -1369,3 +1369,33 @@ ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa CASCADE; ...@@ -1369,3 +1369,33 @@ ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa CASCADE;
CREATE TYPE test_type_empty AS (); CREATE TYPE test_type_empty AS ();
DROP TYPE test_type_empty; DROP TYPE test_type_empty;
--
-- typed tables: OF / NOT OF
--
CREATE TYPE tt_t0 AS (z inet, x int, y numeric(8,2));
ALTER TYPE tt_t0 DROP ATTRIBUTE z;
CREATE TABLE tt0 (x int NOT NULL, y numeric(8,2)); -- OK
CREATE TABLE tt1 (x int, y bigint); -- wrong base type
CREATE TABLE tt2 (x int, y numeric(9,2)); -- wrong typmod
CREATE TABLE tt3 (y numeric(8,2), x int); -- wrong column order
CREATE TABLE tt4 (x int); -- too few columns
CREATE TABLE tt5 (x int, y numeric(8,2), z int); -- too few columns
CREATE TABLE tt6 () INHERITS (tt0); -- can't have a parent
CREATE TABLE tt7 (x int, q text, y numeric(8,2)) WITH OIDS;
ALTER TABLE tt7 DROP q; -- OK
ALTER TABLE tt0 OF tt_t0;
ALTER TABLE tt1 OF tt_t0;
ALTER TABLE tt2 OF tt_t0;
ALTER TABLE tt3 OF tt_t0;
ALTER TABLE tt4 OF tt_t0;
ALTER TABLE tt5 OF tt_t0;
ALTER TABLE tt6 OF tt_t0;
ALTER TABLE tt7 OF tt_t0;
CREATE TYPE tt_t1 AS (x int, y numeric(8,2));
ALTER TABLE tt7 OF tt_t1; -- reassign an already-typed table
ALTER TABLE tt7 NOT OF;
\d tt7
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment