mirror of
https://github.com/postgres/postgres.git
synced 2025-07-31 22:04:40 +03:00
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.
This commit is contained in:
@ -26,15 +26,15 @@ PostgreSQL documentation
|
|||||||
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> <replaceable class="PARAMETER">action</replaceable> [, ... ]
|
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> <replaceable class="PARAMETER">action</replaceable> [, ... ]
|
||||||
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
|
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
|
||||||
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> TO <replaceable class="PARAMETER">new_attribute_name</replaceable>
|
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> TO <replaceable class="PARAMETER">new_attribute_name</replaceable>
|
||||||
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
|
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable> [ CASCADE | RESTRICT ]
|
||||||
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <replaceable class="PARAMETER">new_schema</replaceable>
|
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <replaceable class="PARAMETER">new_schema</replaceable>
|
||||||
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> ]
|
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> ]
|
||||||
|
|
||||||
<phrase>where <replaceable class="PARAMETER">action</replaceable> is one of:</phrase>
|
<phrase>where <replaceable class="PARAMETER">action</replaceable> is one of:</phrase>
|
||||||
|
|
||||||
ADD ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable>
|
ADD ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ CASCADE | RESTRICT ]
|
||||||
DROP ATTRIBUTE [ IF EXISTS ] <replaceable class="PARAMETER">attribute_name</replaceable>
|
DROP ATTRIBUTE [ IF EXISTS ] <replaceable class="PARAMETER">attribute_name</replaceable> [ CASCADE | RESTRICT ]
|
||||||
ALTER ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">data_type</replaceable>
|
ALTER ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> [ SET DATA ] TYPE <replaceable class="PARAMETER">data_type</replaceable> [ CASCADE | RESTRICT ]
|
||||||
</synopsis>
|
</synopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
|
|
||||||
@ -116,6 +116,26 @@ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> ADD VALUE <replacea
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>CASCADE</literal></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Automatically propagate the operation to typed tables of the
|
||||||
|
type being altered.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>RESTRICT</literal></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Refuse the operation if the type being altered is the type of a
|
||||||
|
typed table. This is the default.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
@ -125,11 +125,7 @@ ExecRenameStmt(RenameStmt *stmt)
|
|||||||
}
|
}
|
||||||
case OBJECT_COLUMN:
|
case OBJECT_COLUMN:
|
||||||
case OBJECT_ATTRIBUTE:
|
case OBJECT_ATTRIBUTE:
|
||||||
renameatt(relid,
|
renameatt(relid, stmt);
|
||||||
stmt->subname, /* old att name */
|
|
||||||
stmt->newname, /* new att name */
|
|
||||||
interpretInhOption(stmt->relation->inhOpt), /* recursive? */
|
|
||||||
0); /* expected inhcount */
|
|
||||||
break;
|
break;
|
||||||
case OBJECT_TRIGGER:
|
case OBJECT_TRIGGER:
|
||||||
renametrig(relid,
|
renametrig(relid,
|
||||||
|
@ -269,8 +269,11 @@ static void ATSimpleRecursion(List **wqueue, Relation rel,
|
|||||||
AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode);
|
AlterTableCmd *cmd, bool recurse, LOCKMODE lockmode);
|
||||||
static void ATOneLevelRecursion(List **wqueue, Relation rel,
|
static void ATOneLevelRecursion(List **wqueue, Relation rel,
|
||||||
AlterTableCmd *cmd, LOCKMODE lockmode);
|
AlterTableCmd *cmd, LOCKMODE lockmode);
|
||||||
static void find_typed_table_dependencies(Oid typeOid, const char *typeName);
|
static void ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
|
||||||
static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
|
LOCKMODE lockmode);
|
||||||
|
static List *find_typed_table_dependencies(Oid typeOid, const char *typeName,
|
||||||
|
DropBehavior behavior);
|
||||||
|
static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
|
||||||
AlterTableCmd *cmd, LOCKMODE lockmode);
|
AlterTableCmd *cmd, LOCKMODE lockmode);
|
||||||
static void ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
|
static void ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
|
||||||
ColumnDef *colDef, bool isOid, LOCKMODE lockmode);
|
ColumnDef *colDef, bool isOid, LOCKMODE lockmode);
|
||||||
@ -290,7 +293,8 @@ static void ATExecSetOptions(Relation rel, const char *colName,
|
|||||||
Node *options, bool isReset, LOCKMODE lockmode);
|
Node *options, bool isReset, LOCKMODE lockmode);
|
||||||
static void ATExecSetStorage(Relation rel, const char *colName,
|
static void ATExecSetStorage(Relation rel, const char *colName,
|
||||||
Node *newValue, LOCKMODE lockmode);
|
Node *newValue, LOCKMODE lockmode);
|
||||||
static void ATPrepDropColumn(Relation rel, bool recurse, AlterTableCmd *cmd);
|
static void ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
|
||||||
|
AlterTableCmd *cmd, LOCKMODE lockmode);
|
||||||
static void ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
|
static void ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
|
||||||
DropBehavior behavior,
|
DropBehavior behavior,
|
||||||
bool recurse, bool recursing,
|
bool recurse, bool recursing,
|
||||||
@ -1942,14 +1946,16 @@ setRelhassubclassInRelation(Oid relationId, bool relhassubclass)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* renameatt - changes the name of a attribute in a relation
|
* renameatt_internal - workhorse for renameatt
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
renameatt(Oid myrelid,
|
renameatt_internal(Oid myrelid,
|
||||||
const char *oldattname,
|
const char *oldattname,
|
||||||
const char *newattname,
|
const char *newattname,
|
||||||
bool recurse,
|
bool recurse,
|
||||||
int expected_parents)
|
bool recursing,
|
||||||
|
int expected_parents,
|
||||||
|
DropBehavior behavior)
|
||||||
{
|
{
|
||||||
Relation targetrelation;
|
Relation targetrelation;
|
||||||
Relation attrelation;
|
Relation attrelation;
|
||||||
@ -1964,15 +1970,11 @@ renameatt(Oid myrelid,
|
|||||||
*/
|
*/
|
||||||
targetrelation = relation_open(myrelid, AccessExclusiveLock);
|
targetrelation = relation_open(myrelid, AccessExclusiveLock);
|
||||||
|
|
||||||
if (targetrelation->rd_rel->reloftype)
|
if (targetrelation->rd_rel->reloftype && !recursing)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||||
errmsg("cannot rename column of typed table")));
|
errmsg("cannot rename column of typed table")));
|
||||||
|
|
||||||
if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
|
|
||||||
find_typed_table_dependencies(targetrelation->rd_rel->reltype,
|
|
||||||
RelationGetRelationName(targetrelation));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Renaming the columns of sequences or toast tables doesn't actually
|
* Renaming the columns of sequences or toast tables doesn't actually
|
||||||
* break anything from the system's point of view, since internal
|
* break anything from the system's point of view, since internal
|
||||||
@ -2038,7 +2040,7 @@ renameatt(Oid myrelid,
|
|||||||
if (childrelid == myrelid)
|
if (childrelid == myrelid)
|
||||||
continue;
|
continue;
|
||||||
/* note we need not recurse again */
|
/* note we need not recurse again */
|
||||||
renameatt(childrelid, oldattname, newattname, false, numparents);
|
renameatt_internal(childrelid, oldattname, newattname, false, true, numparents, behavior);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2057,6 +2059,20 @@ renameatt(Oid myrelid,
|
|||||||
oldattname)));
|
oldattname)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* rename attributes in typed tables of composite type */
|
||||||
|
if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
|
||||||
|
{
|
||||||
|
List *child_oids;
|
||||||
|
ListCell *lo;
|
||||||
|
|
||||||
|
child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
|
||||||
|
RelationGetRelationName(targetrelation),
|
||||||
|
behavior);
|
||||||
|
|
||||||
|
foreach(lo, child_oids)
|
||||||
|
renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
|
||||||
|
}
|
||||||
|
|
||||||
attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
|
attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
|
||||||
|
|
||||||
atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
|
atttup = SearchSysCacheCopyAttName(myrelid, oldattname);
|
||||||
@ -2116,6 +2132,22 @@ renameatt(Oid myrelid,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* renameatt - changes the name of a attribute in a relation
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
renameatt(Oid myrelid, RenameStmt *stmt)
|
||||||
|
{
|
||||||
|
renameatt_internal(myrelid,
|
||||||
|
stmt->subname, /* old att name */
|
||||||
|
stmt->newname, /* new att name */
|
||||||
|
interpretInhOption(stmt->relation->inhOpt), /* recursive? */
|
||||||
|
false, /* recursing? */
|
||||||
|
0, /* expected inhcount */
|
||||||
|
stmt->behavior);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute ALTER TABLE/INDEX/SEQUENCE/VIEW RENAME
|
* Execute ALTER TABLE/INDEX/SEQUENCE/VIEW RENAME
|
||||||
*
|
*
|
||||||
@ -2649,14 +2681,14 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
|
|||||||
case AT_AddColumn: /* ADD COLUMN */
|
case AT_AddColumn: /* ADD COLUMN */
|
||||||
ATSimplePermissions(rel, false, true);
|
ATSimplePermissions(rel, false, true);
|
||||||
/* Performs own recursion */
|
/* Performs own recursion */
|
||||||
ATPrepAddColumn(wqueue, rel, recurse, cmd, lockmode);
|
ATPrepAddColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
|
||||||
pass = AT_PASS_ADD_COL;
|
pass = AT_PASS_ADD_COL;
|
||||||
break;
|
break;
|
||||||
case AT_AddColumnToView: /* add column via CREATE OR REPLACE
|
case AT_AddColumnToView: /* add column via CREATE OR REPLACE
|
||||||
* VIEW */
|
* VIEW */
|
||||||
ATSimplePermissions(rel, true, false);
|
ATSimplePermissions(rel, true, false);
|
||||||
/* Performs own recursion */
|
/* Performs own recursion */
|
||||||
ATPrepAddColumn(wqueue, rel, recurse, cmd, lockmode);
|
ATPrepAddColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
|
||||||
pass = AT_PASS_ADD_COL;
|
pass = AT_PASS_ADD_COL;
|
||||||
break;
|
break;
|
||||||
case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
|
case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
|
||||||
@ -2704,7 +2736,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
|
|||||||
break;
|
break;
|
||||||
case AT_DropColumn: /* DROP COLUMN */
|
case AT_DropColumn: /* DROP COLUMN */
|
||||||
ATSimplePermissions(rel, false, true);
|
ATSimplePermissions(rel, false, true);
|
||||||
ATPrepDropColumn(rel, recurse, cmd);
|
ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
|
||||||
/* Recursion occurs during execution phase */
|
/* Recursion occurs during execution phase */
|
||||||
pass = AT_PASS_DROP;
|
pass = AT_PASS_DROP;
|
||||||
break;
|
break;
|
||||||
@ -3671,6 +3703,37 @@ ATOneLevelRecursion(List **wqueue, Relation rel,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ATTypedTableRecursion
|
||||||
|
*
|
||||||
|
* Propagate ALTER TYPE operations to the typed tables of that type.
|
||||||
|
* Also check the RESTRICT/CASCADE behavior.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ATTypedTableRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd,
|
||||||
|
LOCKMODE lockmode)
|
||||||
|
{
|
||||||
|
ListCell *child;
|
||||||
|
List *children;
|
||||||
|
|
||||||
|
Assert(rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE);
|
||||||
|
|
||||||
|
children = find_typed_table_dependencies(rel->rd_rel->reltype,
|
||||||
|
RelationGetRelationName(rel),
|
||||||
|
cmd->behavior);
|
||||||
|
|
||||||
|
foreach(child, children)
|
||||||
|
{
|
||||||
|
Oid childrelid = lfirst_oid(child);
|
||||||
|
Relation childrel;
|
||||||
|
|
||||||
|
childrel = relation_open(childrelid, lockmode);
|
||||||
|
CheckTableNotInUse(childrel, "ALTER TABLE");
|
||||||
|
ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode);
|
||||||
|
relation_close(childrel, NoLock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* find_composite_type_dependencies
|
* find_composite_type_dependencies
|
||||||
@ -3778,17 +3841,17 @@ find_composite_type_dependencies(Oid typeOid,
|
|||||||
* find_typed_table_dependencies
|
* find_typed_table_dependencies
|
||||||
*
|
*
|
||||||
* Check to see if a composite type is being used as the type of a
|
* Check to see if a composite type is being used as the type of a
|
||||||
* typed table. Eventually, we'd like to propagate the alter
|
* typed table. Abort if any are found and behavior is RESTRICT.
|
||||||
* operation into such tables, but for now, just error out if we find
|
* Else return the list of tables.
|
||||||
* any.
|
|
||||||
*/
|
*/
|
||||||
static void
|
static List *
|
||||||
find_typed_table_dependencies(Oid typeOid, const char *typeName)
|
find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior behavior)
|
||||||
{
|
{
|
||||||
Relation classRel;
|
Relation classRel;
|
||||||
ScanKeyData key[1];
|
ScanKeyData key[1];
|
||||||
HeapScanDesc scan;
|
HeapScanDesc scan;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
|
List *result = NIL;
|
||||||
|
|
||||||
classRel = heap_open(RelationRelationId, AccessShareLock);
|
classRel = heap_open(RelationRelationId, AccessShareLock);
|
||||||
|
|
||||||
@ -3801,14 +3864,20 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName)
|
|||||||
|
|
||||||
if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
|
if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
if (behavior == DROP_RESTRICT)
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
ereport(ERROR,
|
||||||
errmsg("cannot alter type \"%s\" because it is the type of a typed table",
|
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
|
||||||
typeName)));
|
errmsg("cannot alter type \"%s\" because it is the type of a typed table",
|
||||||
|
typeName),
|
||||||
|
errhint("Use ALTER ... CASCADE to alter the typed tables too.")));
|
||||||
|
else
|
||||||
|
result = lappend_oid(result, HeapTupleGetOid(tuple));
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_endscan(scan);
|
heap_endscan(scan);
|
||||||
heap_close(classRel, AccessShareLock);
|
heap_close(classRel, AccessShareLock);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3821,10 +3890,10 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName)
|
|||||||
* AlterTableCmd's.
|
* AlterTableCmd's.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
|
ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
|
||||||
AlterTableCmd *cmd, LOCKMODE lockmode)
|
AlterTableCmd *cmd, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
if (rel->rd_rel->reloftype)
|
if (rel->rd_rel->reloftype && !recursing)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||||
errmsg("cannot add column to typed table")));
|
errmsg("cannot add column to typed table")));
|
||||||
@ -3860,8 +3929,7 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
|
if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
|
||||||
find_typed_table_dependencies(rel->rd_rel->reltype,
|
ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
|
||||||
RelationGetRelationName(rel));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -4162,7 +4230,7 @@ ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOC
|
|||||||
cdef->storage = 0;
|
cdef->storage = 0;
|
||||||
cmd->def = (Node *) cdef;
|
cmd->def = (Node *) cdef;
|
||||||
}
|
}
|
||||||
ATPrepAddColumn(wqueue, rel, recurse, cmd, lockmode);
|
ATPrepAddColumn(wqueue, rel, recurse, false, cmd, lockmode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4586,18 +4654,17 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
|
|||||||
* correctly.)
|
* correctly.)
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ATPrepDropColumn(Relation rel, bool recurse, AlterTableCmd *cmd)
|
ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
|
||||||
|
AlterTableCmd *cmd, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
if (rel->rd_rel->reloftype)
|
if (rel->rd_rel->reloftype && !recursing)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||||
errmsg("cannot drop column from typed table")));
|
errmsg("cannot drop column from typed table")));
|
||||||
|
|
||||||
if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
|
if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
|
||||||
find_typed_table_dependencies(rel->rd_rel->reltype,
|
ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
|
||||||
RelationGetRelationName(rel));
|
|
||||||
|
|
||||||
/* No command-specific prep needed except saving recurse flag */
|
|
||||||
if (recurse)
|
if (recurse)
|
||||||
cmd->subtype = AT_DropColumnRecurse;
|
cmd->subtype = AT_DropColumnRecurse;
|
||||||
}
|
}
|
||||||
@ -6060,7 +6127,7 @@ ATPrepAlterColumnType(List **wqueue,
|
|||||||
NewColumnValue *newval;
|
NewColumnValue *newval;
|
||||||
ParseState *pstate = make_parsestate(NULL);
|
ParseState *pstate = make_parsestate(NULL);
|
||||||
|
|
||||||
if (rel->rd_rel->reloftype)
|
if (rel->rd_rel->reloftype && !recursing)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||||
errmsg("cannot alter column type of typed table")));
|
errmsg("cannot alter column type of typed table")));
|
||||||
@ -6178,9 +6245,6 @@ ATPrepAlterColumnType(List **wqueue,
|
|||||||
find_composite_type_dependencies(rel->rd_rel->reltype,
|
find_composite_type_dependencies(rel->rd_rel->reltype,
|
||||||
NULL,
|
NULL,
|
||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
find_typed_table_dependencies(rel->rd_rel->reltype,
|
|
||||||
RelationGetRelationName(rel));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
@ -6198,6 +6262,9 @@ ATPrepAlterColumnType(List **wqueue,
|
|||||||
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
||||||
errmsg("type of inherited column \"%s\" must be changed in child tables too",
|
errmsg("type of inherited column \"%s\" must be changed in child tables too",
|
||||||
colName)));
|
colName)));
|
||||||
|
|
||||||
|
if (tab->relkind == RELKIND_COMPOSITE_TYPE)
|
||||||
|
ATTypedTableRecursion(wqueue, rel, cmd, lockmode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2803,6 +2803,7 @@ _copyRenameStmt(RenameStmt *from)
|
|||||||
COPY_NODE_FIELD(objarg);
|
COPY_NODE_FIELD(objarg);
|
||||||
COPY_STRING_FIELD(subname);
|
COPY_STRING_FIELD(subname);
|
||||||
COPY_STRING_FIELD(newname);
|
COPY_STRING_FIELD(newname);
|
||||||
|
COPY_SCALAR_FIELD(behavior);
|
||||||
|
|
||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
@ -1306,6 +1306,7 @@ _equalRenameStmt(RenameStmt *a, RenameStmt *b)
|
|||||||
COMPARE_NODE_FIELD(objarg);
|
COMPARE_NODE_FIELD(objarg);
|
||||||
COMPARE_STRING_FIELD(subname);
|
COMPARE_STRING_FIELD(subname);
|
||||||
COMPARE_STRING_FIELD(newname);
|
COMPARE_STRING_FIELD(newname);
|
||||||
|
COMPARE_SCALAR_FIELD(behavior);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2003,41 +2003,43 @@ alter_type_cmds:
|
|||||||
;
|
;
|
||||||
|
|
||||||
alter_type_cmd:
|
alter_type_cmd:
|
||||||
/* ALTER TYPE <name> ADD ATTRIBUTE <coldef> */
|
/* ALTER TYPE <name> ADD ATTRIBUTE <coldef> [RESTRICT|CASCADE] */
|
||||||
ADD_P ATTRIBUTE TableFuncElement
|
ADD_P ATTRIBUTE TableFuncElement opt_drop_behavior
|
||||||
{
|
{
|
||||||
AlterTableCmd *n = makeNode(AlterTableCmd);
|
AlterTableCmd *n = makeNode(AlterTableCmd);
|
||||||
n->subtype = AT_AddColumn;
|
n->subtype = AT_AddColumn;
|
||||||
n->def = $3;
|
n->def = $3;
|
||||||
|
n->behavior = $4;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
/* ALTER TYPE <name> DROP ATTRIBUTE IF EXISTS <attname> */
|
/* ALTER TYPE <name> DROP ATTRIBUTE IF EXISTS <attname> [RESTRICT|CASCADE] */
|
||||||
| DROP ATTRIBUTE IF_P EXISTS ColId
|
| DROP ATTRIBUTE IF_P EXISTS ColId opt_drop_behavior
|
||||||
{
|
{
|
||||||
AlterTableCmd *n = makeNode(AlterTableCmd);
|
AlterTableCmd *n = makeNode(AlterTableCmd);
|
||||||
n->subtype = AT_DropColumn;
|
n->subtype = AT_DropColumn;
|
||||||
n->name = $5;
|
n->name = $5;
|
||||||
n->behavior = DROP_RESTRICT; /* currently no effect */
|
n->behavior = $6;
|
||||||
n->missing_ok = TRUE;
|
n->missing_ok = TRUE;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
/* ALTER TYPE <name> DROP ATTRIBUTE <attname> */
|
/* ALTER TYPE <name> DROP ATTRIBUTE <attname> [RESTRICT|CASCADE] */
|
||||||
| DROP ATTRIBUTE ColId opt_drop_behavior
|
| DROP ATTRIBUTE ColId opt_drop_behavior
|
||||||
{
|
{
|
||||||
AlterTableCmd *n = makeNode(AlterTableCmd);
|
AlterTableCmd *n = makeNode(AlterTableCmd);
|
||||||
n->subtype = AT_DropColumn;
|
n->subtype = AT_DropColumn;
|
||||||
n->name = $3;
|
n->name = $3;
|
||||||
n->behavior = DROP_RESTRICT; /* currently no effect */
|
n->behavior = $4;
|
||||||
n->missing_ok = FALSE;
|
n->missing_ok = FALSE;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
/* ALTER TYPE <name> ALTER ATTRIBUTE <attname> [SET DATA] TYPE <typename> */
|
/* ALTER TYPE <name> ALTER ATTRIBUTE <attname> [SET DATA] TYPE <typename> [RESTRICT|CASCADE] */
|
||||||
| ALTER ATTRIBUTE ColId opt_set_data TYPE_P Typename
|
| ALTER ATTRIBUTE ColId opt_set_data TYPE_P Typename opt_drop_behavior
|
||||||
{
|
{
|
||||||
AlterTableCmd *n = makeNode(AlterTableCmd);
|
AlterTableCmd *n = makeNode(AlterTableCmd);
|
||||||
n->subtype = AT_AlterColumnType;
|
n->subtype = AT_AlterColumnType;
|
||||||
n->name = $3;
|
n->name = $3;
|
||||||
n->def = (Node *) $6;
|
n->def = (Node *) $6;
|
||||||
|
n->behavior = $7;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -6005,13 +6007,14 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
|
|||||||
n->newname = $6;
|
n->newname = $6;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
| ALTER TYPE_P any_name RENAME ATTRIBUTE name TO name
|
| ALTER TYPE_P any_name RENAME ATTRIBUTE name TO name opt_drop_behavior
|
||||||
{
|
{
|
||||||
RenameStmt *n = makeNode(RenameStmt);
|
RenameStmt *n = makeNode(RenameStmt);
|
||||||
n->renameType = OBJECT_ATTRIBUTE;
|
n->renameType = OBJECT_ATTRIBUTE;
|
||||||
n->relation = makeRangeVarFromAnyName($3, @3, yyscanner);
|
n->relation = makeRangeVarFromAnyName($3, @3, yyscanner);
|
||||||
n->subname = $6;
|
n->subname = $6;
|
||||||
n->newname = $8;
|
n->newname = $8;
|
||||||
|
n->behavior = $9;
|
||||||
$$ = (Node *)n;
|
$$ = (Node *)n;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -42,11 +42,7 @@ extern void CheckTableNotInUse(Relation rel, const char *stmt);
|
|||||||
|
|
||||||
extern void ExecuteTruncate(TruncateStmt *stmt);
|
extern void ExecuteTruncate(TruncateStmt *stmt);
|
||||||
|
|
||||||
extern void renameatt(Oid myrelid,
|
extern void renameatt(Oid myrelid, RenameStmt *stmt);
|
||||||
const char *oldattname,
|
|
||||||
const char *newattname,
|
|
||||||
bool recurse,
|
|
||||||
int expected_parents);
|
|
||||||
|
|
||||||
extern void RenameRelation(Oid myrelid,
|
extern void RenameRelation(Oid myrelid,
|
||||||
const char *newrelname,
|
const char *newrelname,
|
||||||
|
@ -2073,6 +2073,7 @@ typedef struct RenameStmt
|
|||||||
char *subname; /* name of contained object (column, rule,
|
char *subname; /* name of contained object (column, rule,
|
||||||
* trigger, etc) */
|
* trigger, etc) */
|
||||||
char *newname; /* the new name */
|
char *newname; /* the new name */
|
||||||
|
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
|
||||||
} RenameStmt;
|
} RenameStmt;
|
||||||
|
|
||||||
/* ----------------------
|
/* ----------------------
|
||||||
|
@ -1760,13 +1760,100 @@ ALTER TYPE test_type1 ALTER ATTRIBUTE b TYPE varchar; -- fails
|
|||||||
ERROR: cannot alter type "test_type1" because column "test_tbl1"."y" uses it
|
ERROR: cannot alter type "test_type1" because column "test_tbl1"."y" uses it
|
||||||
CREATE TYPE test_type2 AS (a int, b text);
|
CREATE TYPE test_type2 AS (a int, b text);
|
||||||
CREATE TABLE test_tbl2 OF test_type2;
|
CREATE TABLE test_tbl2 OF test_type2;
|
||||||
|
\d test_type2
|
||||||
|
Composite type "public.test_type2"
|
||||||
|
Column | Type
|
||||||
|
--------+---------
|
||||||
|
a | integer
|
||||||
|
b | text
|
||||||
|
|
||||||
|
\d test_tbl2
|
||||||
|
Table "public.test_tbl2"
|
||||||
|
Column | Type | Modifiers
|
||||||
|
--------+---------+-----------
|
||||||
|
a | integer |
|
||||||
|
b | text |
|
||||||
|
Typed table of type: test_type2
|
||||||
|
|
||||||
ALTER TYPE test_type2 ADD ATTRIBUTE c text; -- fails
|
ALTER TYPE test_type2 ADD ATTRIBUTE c text; -- fails
|
||||||
ERROR: cannot alter type "test_type2" because it is the type of a typed table
|
ERROR: cannot alter type "test_type2" because it is the type of a typed table
|
||||||
|
HINT: Use ALTER ... CASCADE to alter the typed tables too.
|
||||||
|
ALTER TYPE test_type2 ADD ATTRIBUTE c text CASCADE;
|
||||||
|
\d test_type2
|
||||||
|
Composite type "public.test_type2"
|
||||||
|
Column | Type
|
||||||
|
--------+---------
|
||||||
|
a | integer
|
||||||
|
b | text
|
||||||
|
c | text
|
||||||
|
|
||||||
|
\d test_tbl2
|
||||||
|
Table "public.test_tbl2"
|
||||||
|
Column | Type | Modifiers
|
||||||
|
--------+---------+-----------
|
||||||
|
a | integer |
|
||||||
|
b | text |
|
||||||
|
c | text |
|
||||||
|
Typed table of type: test_type2
|
||||||
|
|
||||||
ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar; -- fails
|
ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar; -- fails
|
||||||
ERROR: cannot alter type "test_type2" because it is the type of a typed table
|
ERROR: cannot alter type "test_type2" because it is the type of a typed table
|
||||||
|
HINT: Use ALTER ... CASCADE to alter the typed tables too.
|
||||||
|
ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar CASCADE;
|
||||||
|
\d test_type2
|
||||||
|
Composite type "public.test_type2"
|
||||||
|
Column | Type
|
||||||
|
--------+-------------------
|
||||||
|
a | integer
|
||||||
|
b | character varying
|
||||||
|
c | text
|
||||||
|
|
||||||
|
\d test_tbl2
|
||||||
|
Table "public.test_tbl2"
|
||||||
|
Column | Type | Modifiers
|
||||||
|
--------+-------------------+-----------
|
||||||
|
a | integer |
|
||||||
|
b | character varying |
|
||||||
|
c | text |
|
||||||
|
Typed table of type: test_type2
|
||||||
|
|
||||||
ALTER TYPE test_type2 DROP ATTRIBUTE b; -- fails
|
ALTER TYPE test_type2 DROP ATTRIBUTE b; -- fails
|
||||||
ERROR: cannot alter type "test_type2" because it is the type of a typed table
|
ERROR: cannot alter type "test_type2" because it is the type of a typed table
|
||||||
ALTER TYPE test_type2 RENAME ATTRIBUTE b TO bb; -- fails
|
HINT: Use ALTER ... CASCADE to alter the typed tables too.
|
||||||
|
ALTER TYPE test_type2 DROP ATTRIBUTE b CASCADE;
|
||||||
|
\d test_type2
|
||||||
|
Composite type "public.test_type2"
|
||||||
|
Column | Type
|
||||||
|
--------+---------
|
||||||
|
a | integer
|
||||||
|
c | text
|
||||||
|
|
||||||
|
\d test_tbl2
|
||||||
|
Table "public.test_tbl2"
|
||||||
|
Column | Type | Modifiers
|
||||||
|
--------+---------+-----------
|
||||||
|
a | integer |
|
||||||
|
c | text |
|
||||||
|
Typed table of type: test_type2
|
||||||
|
|
||||||
|
ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa; -- fails
|
||||||
ERROR: cannot alter type "test_type2" because it is the type of a typed table
|
ERROR: cannot alter type "test_type2" because it is the type of a typed table
|
||||||
|
HINT: Use ALTER ... CASCADE to alter the typed tables too.
|
||||||
|
ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa CASCADE;
|
||||||
|
\d test_type2
|
||||||
|
Composite type "public.test_type2"
|
||||||
|
Column | Type
|
||||||
|
--------+---------
|
||||||
|
aa | integer
|
||||||
|
c | text
|
||||||
|
|
||||||
|
\d test_tbl2
|
||||||
|
Table "public.test_tbl2"
|
||||||
|
Column | Type | Modifiers
|
||||||
|
--------+---------+-----------
|
||||||
|
aa | integer |
|
||||||
|
c | text |
|
||||||
|
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;
|
||||||
|
@ -1272,10 +1272,28 @@ ALTER TYPE test_type1 ALTER ATTRIBUTE b TYPE varchar; -- fails
|
|||||||
|
|
||||||
CREATE TYPE test_type2 AS (a int, b text);
|
CREATE TYPE test_type2 AS (a int, b text);
|
||||||
CREATE TABLE test_tbl2 OF test_type2;
|
CREATE TABLE test_tbl2 OF test_type2;
|
||||||
|
\d test_type2
|
||||||
|
\d test_tbl2
|
||||||
|
|
||||||
ALTER TYPE test_type2 ADD ATTRIBUTE c text; -- fails
|
ALTER TYPE test_type2 ADD ATTRIBUTE c text; -- fails
|
||||||
|
ALTER TYPE test_type2 ADD ATTRIBUTE c text CASCADE;
|
||||||
|
\d test_type2
|
||||||
|
\d test_tbl2
|
||||||
|
|
||||||
ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar; -- fails
|
ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar; -- fails
|
||||||
|
ALTER TYPE test_type2 ALTER ATTRIBUTE b TYPE varchar CASCADE;
|
||||||
|
\d test_type2
|
||||||
|
\d test_tbl2
|
||||||
|
|
||||||
ALTER TYPE test_type2 DROP ATTRIBUTE b; -- fails
|
ALTER TYPE test_type2 DROP ATTRIBUTE b; -- fails
|
||||||
ALTER TYPE test_type2 RENAME ATTRIBUTE b TO bb; -- fails
|
ALTER TYPE test_type2 DROP ATTRIBUTE b CASCADE;
|
||||||
|
\d test_type2
|
||||||
|
\d test_tbl2
|
||||||
|
|
||||||
|
ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa; -- fails
|
||||||
|
ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa CASCADE;
|
||||||
|
\d test_type2
|
||||||
|
\d test_tbl2
|
||||||
|
|
||||||
CREATE TYPE test_type_empty AS ();
|
CREATE TYPE test_type_empty AS ();
|
||||||
DROP TYPE test_type_empty;
|
DROP TYPE test_type_empty;
|
||||||
|
Reference in New Issue
Block a user