Skip to content

Commit f2a4278

Browse files
committed
Propagate ALTER TYPE operations to typed tables
This adds RESTRICT/CASCADE flags to ALTER TYPE ... ADD/DROP/ALTER/ RENAME ATTRIBUTE to control whether to alter typed tables as well.
1 parent fc946c3 commit f2a4278

File tree

10 files changed

+258
-68
lines changed

10 files changed

+258
-68
lines changed

doc/src/sgml/ref/alter_type.sgml

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@ PostgreSQL documentation
2626
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> <replaceable class="PARAMETER">action</replaceable> [, ... ]
2727
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
2828
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> TO <replaceable class="PARAMETER">new_attribute_name</replaceable>
29-
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
29+
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable> [ CASCADE | RESTRICT ]
3030
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <replaceable class="PARAMETER">new_schema</replaceable>
3131
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> ADD VALUE <replaceable class="PARAMETER">new_enum_value</replaceable> [ { BEFORE | AFTER } <replaceable class="PARAMETER">existing_enum_value</replaceable> ]
3232

3333
<phrase>where <replaceable class="PARAMETER">action</replaceable> is one of:</phrase>
3434

35-
ADD ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable>
36-
DROP ATTRIBUTE [ IF EXISTS ] <replaceable class="PARAMETER">attribute_name</replaceable>
37-
ALTER ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">data_type</replaceable>
35+
ADD ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ CASCADE | RESTRICT ]
36+
DROP ATTRIBUTE [ IF EXISTS ] <replaceable class="PARAMETER">attribute_name</replaceable> [ CASCADE | RESTRICT ]
37+
ALTER ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">data_type</replaceable> [ CASCADE | RESTRICT ]
3838
</synopsis>
3939
</refsynopsisdiv>
4040

@@ -116,6 +116,26 @@ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> ADD VALUE <replacea
116116
</para>
117117
</listitem>
118118
</varlistentry>
119+
120+
<varlistentry>
121+
<term><literal>CASCADE</literal></term>
122+
<listitem>
123+
<para>
124+
Automatically propagate the operation to typed tables of the
125+
type being altered.
126+
</para>
127+
</listitem>
128+
</varlistentry>
129+
130+
<varlistentry>
131+
<term><literal>RESTRICT</literal></term>
132+
<listitem>
133+
<para>
134+
Refuse the operation if the type being altered is the type of a
135+
typed table. This is the default.
136+
</para>
137+
</listitem>
138+
</varlistentry>
119139
</variablelist>
120140
</para>
121141

src/backend/commands/alter.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,7 @@ ExecRenameStmt(RenameStmt *stmt)
125125
}
126126
case OBJECT_COLUMN:
127127
case OBJECT_ATTRIBUTE:
128-
renameatt(relid,
129-
stmt->subname, /* old att name */
130-
stmt->newname, /* new att name */
131-
interpretInhOption(stmt->relation->inhOpt), /* recursive? */
132-
0); /* expected inhcount */
128+
renameatt(relid, stmt);
133129
break;
134130
case OBJECT_TRIGGER:
135131
renametrig(relid,

src/backend/commands/tablecmds.c

Lines changed: 109 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,11 @@ static void ATSimpleRecursion(List **wqueue, Relation rel,
269269
AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode);
270270
static void ATOneLevelRecursion(List **wqueue, Relation rel,
271271
AlterTableCmd *cmd, LOCKMODE lockmode);
272-
static void find_typed_table_dependencies(Oid typeOid, const char *typeName);
273-
static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
272+
static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
273+
LOCKMODE lockmode);
274+
static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
275+
DropBehavior behavior);
276+
static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
274277
AlterTableCmd *cmd, LOCKMODE lockmode);
275278
static void ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
276279
ColumnDef *colDef, bool isOid, LOCKMODE lockmode);
@@ -290,7 +293,8 @@ static void ATExecSetOptions(Relation rel, const char *colName,
290293
Node *options, bool isReset, LOCKMODE lockmode);
291294
static void ATExecSetStorage(Relation rel, const char *colName,
292295
Node *newValue, LOCKMODE lockmode);
293-
static void ATPrepDropColumn(Relation rel, bool recurse, AlterTableCmd *cmd);
296+
static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
297+
AlterTableCmd *cmd, LOCKMODE lockmode);
294298
static void ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
295299
DropBehavior behavior,
296300
bool recurse, bool recursing,
@@ -1942,14 +1946,16 @@ setRelhassubclassInRelation(Oid relationId, bool relhassubclass)
19421946

19431947

19441948
/*
1945-
* renameatt - changes the name of a attribute in a relation
1949+
* renameatt_internal - workhorse for renameatt
19461950
*/
1947-
void
1948-
renameatt(Oid myrelid,
1949-
const char *oldattname,
1950-
const char *newattname,
1951-
bool recurse,
1952-
int expected_parents)
1951+
static void
1952+
renameatt_internal(Oid myrelid,
1953+
const char *oldattname,
1954+
const char *newattname,
1955+
bool recurse,
1956+
bool recursing,
1957+
int expected_parents,
1958+
DropBehavior behavior)
19531959
{
19541960
Relation targetrelation;
19551961
Relation attrelation;
@@ -1964,15 +1970,11 @@ renameatt(Oid myrelid,
19641970
*/
19651971
targetrelation = relation_open(myrelid, AccessExclusiveLock);
19661972

1967-
if (targetrelation->rd_rel->reloftype)
1973+
if (targetrelation->rd_rel->reloftype && !recursing)
19681974
ereport(ERROR,
19691975
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
19701976
errmsg("cannot rename column of typed table")));
19711977

1972-
if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
1973-
find_typed_table_dependencies(targetrelation->rd_rel->reltype,
1974-
RelationGetRelationName(targetrelation));
1975-
19761978
/*
19771979
* Renaming the columns of sequences or toast tables doesn't actually
19781980
* break anything from the system's point of view, since internal
@@ -2038,7 +2040,7 @@ renameatt(Oid myrelid,
20382040
if (childrelid == myrelid)
20392041
continue;
20402042
/* note we need not recurse again */
2041-
renameatt(childrelid, oldattname, newattname, false, numparents);
2043+
renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
20422044
}
20432045
}
20442046
else
@@ -2057,6 +2059,20 @@ renameatt(Oid myrelid,
20572059
oldattname)));
20582060
}
20592061

2062+
/* rename attributes in typed tables of composite type */
2063+
if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
2064+
{
2065+
List *child_oids;
2066+
ListCell *lo;
2067+
2068+
child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
2069+
RelationGetRelationName(targetrelation),
2070+
behavior);
2071+
2072+
foreach(lo, child_oids)
2073+
renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
2074+
}
2075+
20602076
attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
20612077

20622078
atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
@@ -2116,6 +2132,22 @@ renameatt(Oid myrelid,
21162132
}
21172133

21182134

2135+
/*
2136+
* renameatt - changes the name of a attribute in a relation
2137+
*/
2138+
void
2139+
renameatt(Oid myrelid, RenameStmt *stmt)
2140+
{
2141+
renameatt_internal(myrelid,
2142+
stmt->subname, /* old att name */
2143+
stmt->newname, /* new att name */
2144+
interpretInhOption(stmt->relation->inhOpt), /* recursive? */
2145+
false, /* recursing? */
2146+
0, /* expected inhcount */
2147+
stmt->behavior);
2148+
}
2149+
2150+
21192151
/*
21202152
* Execute ALTER TABLE/INDEX/SEQUENCE/VIEW RENAME
21212153
*
@@ -2649,14 +2681,14 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
26492681
case AT_AddColumn: /* ADD COLUMN */
26502682
ATSimplePermissions(rel, false, true);
26512683
/* Performs own recursion */
2652-
ATPrepAddColumn(wqueue, rel, recurse, cmd, lockmode);
2684+
ATPrepAddColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
26532685
pass = AT_PASS_ADD_COL;
26542686
break;
26552687
case AT_AddColumnToView: /* add column via CREATE OR REPLACE
26562688
* VIEW */
26572689
ATSimplePermissions(rel, true, false);
26582690
/* Performs own recursion */
2659-
ATPrepAddColumn(wqueue, rel, recurse, cmd, lockmode);
2691+
ATPrepAddColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
26602692
pass = AT_PASS_ADD_COL;
26612693
break;
26622694
case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
@@ -2704,7 +2736,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
27042736
break;
27052737
case AT_DropColumn: /* DROP COLUMN */
27062738
ATSimplePermissions(rel, false, true);
2707-
ATPrepDropColumn(rel, recurse, cmd);
2739+
ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
27082740
/* Recursion occurs during execution phase */
27092741
pass = AT_PASS_DROP;
27102742
break;
@@ -3671,6 +3703,37 @@ ATOneLevelRecursion(List **wqueue, Relation rel,
36713703
}
36723704
}
36733705

3706+
/*
3707+
* ATTypedTableRecursion
3708+
*
3709+
* Propagate ALTER TYPE operations to the typed tables of that type.
3710+
* Also check the RESTRICT/CASCADE behavior.
3711+
*/
3712+
static void
3713+
ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
3714+
LOCKMODE lockmode)
3715+
{
3716+
ListCell *child;
3717+
List *children;
3718+
3719+
Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
3720+
3721+
children = find_typed_table_dependencies(rel->rd_rel->reltype,
3722+
RelationGetRelationName(rel),
3723+
cmd->behavior);
3724+
3725+
foreach(child, children)
3726+
{
3727+
Oid childrelid = lfirst_oid(child);
3728+
Relation childrel;
3729+
3730+
childrel = relation_open(childrelid, lockmode);
3731+
CheckTableNotInUse(childrel, "ALTER TABLE");
3732+
ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode);
3733+
relation_close(childrel, NoLock);
3734+
}
3735+
}
3736+
36743737

36753738
/*
36763739
* find_composite_type_dependencies
@@ -3778,17 +3841,17 @@ find_composite_type_dependencies(Oid typeOid,
37783841
* find_typed_table_dependencies
37793842
*
37803843
* Check to see if a composite type is being used as the type of a
3781-
* typed table. Eventually, we'd like to propagate the alter
3782-
* operation into such tables, but for now, just error out if we find
3783-
* any.
3844+
* typed table. Abort if any are found and behavior is RESTRICT.
3845+
* Else return the list of tables.
37843846
*/
3785-
static void
3786-
find_typed_table_dependencies(Oid typeOid, const char *typeName)
3847+
static List *
3848+
find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
37873849
{
37883850
Relation classRel;
37893851
ScanKeyData key[1];
37903852
HeapScanDesc scan;
37913853
HeapTuple tuple;
3854+
List *result = NIL;
37923855

37933856
classRel = heap_open(RelationRelationId, AccessShareLock);
37943857

@@ -3801,14 +3864,20 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName)
38013864

38023865
if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
38033866
{
3804-
ereport(ERROR,
3805-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3806-
errmsg("cannot alter type \"%s\" because it is the type of a typed table",
3807-
typeName)));
3867+
if (behavior == DROP_RESTRICT)
3868+
ereport(ERROR,
3869+
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
3870+
errmsg("cannot alter type \"%s\" because it is the type of a typed table",
3871+
typeName),
3872+
errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
3873+
else
3874+
result = lappend_oid(result, HeapTupleGetOid(tuple));
38083875
}
38093876

38103877
heap_endscan(scan);
38113878
heap_close(classRel, AccessShareLock);
3879+
3880+
return result;
38123881
}
38133882

38143883

@@ -3821,10 +3890,10 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName)
38213890
* AlterTableCmd's.
38223891
*/
38233892
static void
3824-
ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
3893+
ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
38253894
AlterTableCmd *cmd, LOCKMODE lockmode)
38263895
{
3827-
if (rel->rd_rel->reloftype)
3896+
if (rel->rd_rel->reloftype && !recursing)
38283897
ereport(ERROR,
38293898
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
38303899
errmsg("cannot add column to typed table")));
@@ -3860,8 +3929,7 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
38603929
}
38613930

38623931
if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
3863-
find_typed_table_dependencies(rel->rd_rel->reltype,
3864-
RelationGetRelationName(rel));
3932+
ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
38653933
}
38663934

38673935
static void
@@ -4162,7 +4230,7 @@ ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOC
41624230
cdef->storage = 0;
41634231
cmd->def = (Node *) cdef;
41644232
}
4165-
ATPrepAddColumn(wqueue, rel, recurse, cmd, lockmode);
4233+
ATPrepAddColumn(wqueue, rel, recurse, false, cmd, lockmode);
41664234
}
41674235

41684236
/*
@@ -4586,18 +4654,17 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
45864654
* correctly.)
45874655
*/
45884656
static void
4589-
ATPrepDropColumn(Relation rel, bool recurse, AlterTableCmd *cmd)
4657+
ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
4658+
AlterTableCmd *cmd, LOCKMODE lockmode)
45904659
{
4591-
if (rel->rd_rel->reloftype)
4660+
if (rel->rd_rel->reloftype && !recursing)
45924661
ereport(ERROR,
45934662
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
45944663
errmsg("cannot drop column from typed table")));
45954664

45964665
if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
4597-
find_typed_table_dependencies(rel->rd_rel->reltype,
4598-
RelationGetRelationName(rel));
4666+
ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
45994667

4600-
/* No command-specific prep needed except saving recurse flag */
46014668
if (recurse)
46024669
cmd->subtype = AT_DropColumnRecurse;
46034670
}
@@ -6060,7 +6127,7 @@ ATPrepAlterColumnType(List **wqueue,
60606127
NewColumnValue *newval;
60616128
ParseState *pstate = make_parsestate(NULL);
60626129

6063-
if (rel->rd_rel->reloftype)
6130+
if (rel->rd_rel->reloftype && !recursing)
60646131
ereport(ERROR,
60656132
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
60666133
errmsg("cannot alter column type of typed table")));
@@ -6178,9 +6245,6 @@ ATPrepAlterColumnType(List **wqueue,
61786245
find_composite_type_dependencies(rel->rd_rel->reltype,
61796246
NULL,
61806247
RelationGetRelationName(rel));
6181-
6182-
find_typed_table_dependencies(rel->rd_rel->reltype,
6183-
RelationGetRelationName(rel));
61846248
}
61856249

61866250
ReleaseSysCache(tuple);
@@ -6198,6 +6262,9 @@ ATPrepAlterColumnType(List **wqueue,
61986262
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
61996263
errmsg("type of inherited column \"%s\" must be changed in child tables too",
62006264
colName)));
6265+
6266+
if (tab->relkind == RELKIND_COMPOSITE_TYPE)
6267+
ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
62016268
}
62026269

62036270
static void

src/backend/nodes/copyfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2803,6 +2803,7 @@ _copyRenameStmt(RenameStmt *from)
28032803
COPY_NODE_FIELD(objarg);
28042804
COPY_STRING_FIELD(subname);
28052805
COPY_STRING_FIELD(newname);
2806+
COPY_SCALAR_FIELD(behavior);
28062807

28072808
return newnode;
28082809
}

src/backend/nodes/equalfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,7 @@ _equalRenameStmt(RenameStmt *a, RenameStmt *b)
13061306
COMPARE_NODE_FIELD(objarg);
13071307
COMPARE_STRING_FIELD(subname);
13081308
COMPARE_STRING_FIELD(newname);
1309+
COMPARE_SCALAR_FIELD(behavior);
13091310

13101311
return true;
13111312
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy