mirror of
https://github.com/postgres/postgres.git
synced 2025-06-17 17:02:08 +03:00
Add IF NOT EXISTS processing to ALTER TABLE ADD COLUMN
Fabrízio de Royes Mello, reviewed by Payal Singh, Alvaro Herrera and Michael Paquier.
This commit is contained in:
@ -328,8 +328,9 @@ static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recu
|
||||
bool is_view, AlterTableCmd *cmd, LOCKMODE lockmode);
|
||||
static ObjectAddress ATExecAddColumn(List **wqueue, AlteredTableInfo *tab,
|
||||
Relation rel, ColumnDef *colDef, bool isOid,
|
||||
bool recurse, bool recursing, LOCKMODE lockmode);
|
||||
static void check_for_column_name_collision(Relation rel, const char *colname);
|
||||
bool recurse, bool recursing, bool if_not_exists, LOCKMODE lockmode);
|
||||
static bool check_for_column_name_collision(Relation rel, const char *colname,
|
||||
bool if_not_exists);
|
||||
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
|
||||
static void add_column_collation_dependency(Oid relid, int32 attnum, Oid collid);
|
||||
static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse,
|
||||
@ -2304,7 +2305,7 @@ renameatt_internal(Oid myrelid,
|
||||
oldattname)));
|
||||
|
||||
/* new name should not already exist */
|
||||
check_for_column_name_collision(targetrelation, newattname);
|
||||
(void) check_for_column_name_collision(targetrelation, newattname, false);
|
||||
|
||||
/* apply the update */
|
||||
namestrcpy(&(attform->attname), newattname);
|
||||
@ -3455,11 +3456,11 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
case AT_AddColumnToView: /* add column via CREATE OR REPLACE
|
||||
* VIEW */
|
||||
address = ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
|
||||
false, false, false, lockmode);
|
||||
false, false, false, false, lockmode);
|
||||
break;
|
||||
case AT_AddColumnRecurse:
|
||||
address = ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
|
||||
false, true, false, lockmode);
|
||||
false, true, false, cmd->missing_ok, lockmode);
|
||||
break;
|
||||
case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
|
||||
address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
|
||||
@ -3572,14 +3573,14 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
if (cmd->def != NULL)
|
||||
address =
|
||||
ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
|
||||
true, false, false, lockmode);
|
||||
true, false, false, cmd->missing_ok, lockmode);
|
||||
break;
|
||||
case AT_AddOidsRecurse: /* SET WITH OIDS */
|
||||
/* Use the ADD COLUMN code, unless prep decided to do nothing */
|
||||
if (cmd->def != NULL)
|
||||
address =
|
||||
ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
|
||||
true, true, false, lockmode);
|
||||
true, true, false, cmd->missing_ok, lockmode);
|
||||
break;
|
||||
case AT_DropOids: /* SET WITHOUT OIDS */
|
||||
|
||||
@ -4677,7 +4678,7 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
|
||||
static ObjectAddress
|
||||
ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
ColumnDef *colDef, bool isOid,
|
||||
bool recurse, bool recursing, LOCKMODE lockmode)
|
||||
bool recurse, bool recursing, bool if_not_exists, LOCKMODE lockmode)
|
||||
{
|
||||
Oid myrelid = RelationGetRelid(rel);
|
||||
Relation pgclass,
|
||||
@ -4771,8 +4772,14 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
elog(ERROR, "cache lookup failed for relation %u", myrelid);
|
||||
relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
|
||||
|
||||
/* new name should not already exist */
|
||||
check_for_column_name_collision(rel, colDef->colname);
|
||||
/* skip if the name already exists and if_not_exists is true */
|
||||
if (!check_for_column_name_collision(rel, colDef->colname, if_not_exists))
|
||||
{
|
||||
heap_close(attrdesc, RowExclusiveLock);
|
||||
heap_freetuple(reltup);
|
||||
heap_close(pgclass, RowExclusiveLock);
|
||||
return InvalidObjectAddress;
|
||||
}
|
||||
|
||||
/* Determine the new attribute's number */
|
||||
if (isOid)
|
||||
@ -5002,7 +5009,8 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
|
||||
/* Recurse to child; return value is ignored */
|
||||
ATExecAddColumn(wqueue, childtab, childrel,
|
||||
colDef, isOid, recurse, true, lockmode);
|
||||
colDef, isOid, recurse, true,
|
||||
if_not_exists, lockmode);
|
||||
|
||||
heap_close(childrel, NoLock);
|
||||
}
|
||||
@ -5013,10 +5021,11 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
|
||||
|
||||
/*
|
||||
* If a new or renamed column will collide with the name of an existing
|
||||
* column, error out.
|
||||
* column and if_not_exists is false then error out, else do nothing.
|
||||
*/
|
||||
static void
|
||||
check_for_column_name_collision(Relation rel, const char *colname)
|
||||
static bool
|
||||
check_for_column_name_collision(Relation rel, const char *colname,
|
||||
bool if_not_exists)
|
||||
{
|
||||
HeapTuple attTuple;
|
||||
int attnum;
|
||||
@ -5029,7 +5038,7 @@ check_for_column_name_collision(Relation rel, const char *colname)
|
||||
ObjectIdGetDatum(RelationGetRelid(rel)),
|
||||
PointerGetDatum(colname));
|
||||
if (!HeapTupleIsValid(attTuple))
|
||||
return;
|
||||
return true;
|
||||
|
||||
attnum = ((Form_pg_attribute) GETSTRUCT(attTuple))->attnum;
|
||||
ReleaseSysCache(attTuple);
|
||||
@ -5045,10 +5054,23 @@ check_for_column_name_collision(Relation rel, const char *colname)
|
||||
errmsg("column name \"%s\" conflicts with a system column name",
|
||||
colname)));
|
||||
else
|
||||
{
|
||||
if (if_not_exists)
|
||||
{
|
||||
ereport(NOTICE,
|
||||
(errcode(ERRCODE_DUPLICATE_COLUMN),
|
||||
errmsg("column \"%s\" of relation \"%s\" already exists, skipping",
|
||||
colname, RelationGetRelationName(rel))));
|
||||
return false;
|
||||
}
|
||||
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DUPLICATE_COLUMN),
|
||||
errmsg("column \"%s\" of relation \"%s\" already exists",
|
||||
colname, RelationGetRelationName(rel))));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user