@ -285,16 +285,15 @@ static void ATSimplePermissions(Relation rel, int allowed_targets);
static void ATWrongRelkindError ( Relation rel , int allowed_targets ) ;
static void ATSimpleRecursion ( List * * wqueue , Relation rel ,
AlterTableCmd * cmd , bool recurse , LOCKMODE lockmode ) ;
static void ATOneLevelRecursion ( List * * wqueue , Relation rel ,
AlterTableCmd * cmd , LOCKMODE lockmode ) ;
static void ATTypedTableRecursion ( List * * wqueue , Relation rel , AlterTableCmd * cmd ,
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 ) ;
static void ATExecAddColumn ( AlteredTableInfo * tab , Relation rel ,
ColumnDef * colDef , bool isOid , LOCKMODE lockmode ) ;
static void ATExecAddColumn ( List * * wqueue , AlteredTableInfo * tab , Relation rel ,
ColumnDef * colDef , bool isOid ,
bool recurse , bool recursing , LOCKMODE lockmode ) ;
static void add_column_datatype_dependency ( Oid relid , int32 attnum , Oid typid , Oid collid ) ;
static void ATPrepAddOids ( List * * wqueue , Relation rel , bool recurse ,
AlterTableCmd * cmd , LOCKMODE lockmode ) ;
@ -2775,15 +2774,15 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
case AT_AddColumn : /* ADD COLUMN */
ATSimplePermissions ( rel ,
ATT_TABLE | ATT_COMPOSITE_TYPE | ATT_FOREIGN_TABLE ) ;
/* Performs own recursion */
ATPrepAddColumn ( wqueue , rel , recurse , recursing , cmd , lockmode ) ;
/* Recursion occurs during execution phase */
pass = AT_PASS_ADD_COL ;
break ;
case AT_AddColumnToView : /* add column via CREATE OR REPLACE
* VIEW */
ATSimplePermissions ( rel , ATT_VIEW ) ;
/* Performs own recursion */
ATPrepAddColumn ( wqueue , rel , recurse , recursing , cmd , lockmode ) ;
/* Recursion occurs during execution phase */
pass = AT_PASS_ADD_COL ;
break ;
case AT_ColumnDefault : /* ALTER COLUMN DEFAULT */
@ -2885,9 +2884,9 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
break ;
case AT_AddOids : /* SET WITH OIDS */
ATSimplePermissions ( rel , ATT_TABLE ) ;
/* Performs own recursion */
if ( ! rel - > rd_rel - > relhasoids | | recursing )
ATPrepAddOids ( wqueue , rel , recurse , cmd , lockmode ) ;
/* Recursion occurs during execution phase */
pass = AT_PASS_ADD_COL ;
break ;
case AT_DropOids : /* SET WITHOUT OIDS */
@ -3043,7 +3042,12 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
case AT_AddColumn : /* ADD COLUMN */
case AT_AddColumnToView : /* add column via CREATE OR REPLACE
* VIEW */
ATExecAddColumn ( tab , rel , ( ColumnDef * ) cmd - > def , false , lockmode ) ;
ATExecAddColumn ( wqueue , tab , rel , ( ColumnDef * ) cmd - > def ,
false , false , false , lockmode ) ;
break ;
case AT_AddColumnRecurse :
ATExecAddColumn ( wqueue , tab , rel , ( ColumnDef * ) cmd - > def ,
false , true , false , lockmode ) ;
break ;
case AT_ColumnDefault : /* ALTER COLUMN DEFAULT */
ATExecColumnDefault ( rel , cmd - > name , cmd - > def , lockmode ) ;
@ -3121,7 +3125,14 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
case AT_AddOids : /* SET WITH OIDS */
/* Use the ADD COLUMN code, unless prep decided to do nothing */
if ( cmd - > def ! = NULL )
ATExecAddColumn ( tab , rel , ( ColumnDef * ) cmd - > def , true , lockmode ) ;
ATExecAddColumn ( wqueue , tab , rel , ( ColumnDef * ) cmd - > def ,
true , false , false , lockmode ) ;
break ;
case AT_AddOidsRecurse : /* SET WITH OIDS */
/* Use the ADD COLUMN code, unless prep decided to do nothing */
if ( cmd - > def ! = NULL )
ATExecAddColumn ( wqueue , tab , rel , ( ColumnDef * ) cmd - > def ,
true , true , false , lockmode ) ;
break ;
case AT_DropOids : /* SET WITHOUT OIDS */
@ -3842,37 +3853,6 @@ ATSimpleRecursion(List **wqueue, Relation rel,
}
}
/*
* ATOneLevelRecursion
*
* Here , we visit only direct inheritance children . It is expected that
* the command ' s prep routine will recurse again to find indirect children .
* When using this technique , a multiply - inheriting child will be visited
* multiple times .
*/
static void
ATOneLevelRecursion ( List * * wqueue , Relation rel ,
AlterTableCmd * cmd , LOCKMODE lockmode )
{
Oid relid = RelationGetRelid ( rel ) ;
ListCell * child ;
List * children ;
children = find_inheritance_children ( relid , lockmode ) ;
foreach ( child , children )
{
Oid childrelid = lfirst_oid ( child ) ;
Relation childrel ;
/* find_inheritance_children already got lock */
childrel = relation_open ( childrelid , NoLock ) ;
CheckTableNotInUse ( childrel , " ALTER TABLE " ) ;
ATPrepCmd ( wqueue , childrel , cmd , true , true , lockmode ) ;
relation_close ( childrel , NoLock ) ;
}
}
/*
* ATTypedTableRecursion
*
@ -4060,6 +4040,12 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior be
* CHECK , NOT NULL , and FOREIGN KEY constraints will be removed from the
* AT_AddColumn AlterTableCmd by parse_utilcmd . c and added as independent
* AlterTableCmd ' s .
*
* ADD COLUMN cannot use the normal ALTER TABLE recursion mechanism , because we
* have to decide at runtime whether to recurse or not depending on whether we
* actually add a column or merely merge with an existing column . ( We can ' t
* check this in a static pre - pass because it won ' t handle multiple inheritance
* situations correctly . )
*/
static void
ATPrepAddColumn ( List * * wqueue , Relation rel , bool recurse , bool recursing ,
@ -4070,43 +4056,17 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
( errcode ( ERRCODE_WRONG_OBJECT_TYPE ) ,
errmsg ( " cannot add column to typed table " ) ) ) ;
/*
* Recurse to add the column to child classes , if requested .
*
* We must recurse one level at a time , so that multiply - inheriting
* children are visited the right number of times and end up with the
* right attinhcount .
*/
if ( recurse )
{
AlterTableCmd * childCmd = copyObject ( cmd ) ;
ColumnDef * colDefChild = ( ColumnDef * ) childCmd - > def ;
/* Child should see column as singly inherited */
colDefChild - > inhcount = 1 ;
colDefChild - > is_local = false ;
ATOneLevelRecursion ( wqueue , rel , childCmd , lockmode ) ;
}
else
{
/*
* If we are told not to recurse , there had better not be any child
* tables ; else the addition would put them out of step .
*/
if ( find_inheritance_children ( RelationGetRelid ( rel ) , NoLock ) ! = NIL )
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_TABLE_DEFINITION ) ,
errmsg ( " column must be added to child tables too " ) ) ) ;
}
if ( rel - > rd_rel - > relkind = = RELKIND_COMPOSITE_TYPE )
ATTypedTableRecursion ( wqueue , rel , cmd , lockmode ) ;
if ( recurse )
cmd - > subtype = AT_AddColumnRecurse ;
}
static void
ATExecAddColumn ( AlteredTableInfo * tab , Relation rel ,
ColumnDef * colDef , bool isOid , LOCKMODE lockmode )
ATExecAddColumn ( List * * wqueue , AlteredTableInfo * tab , Relation rel ,
ColumnDef * colDef , bool isOid ,
bool recurse , bool recursing , LOCKMODE lockmode )
{
Oid myrelid = RelationGetRelid ( rel ) ;
Relation pgclass ,
@ -4121,12 +4081,20 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
Oid collOid ;
Form_pg_type tform ;
Expr * defval ;
List * children ;
ListCell * child ;
/* At top level, permission check was done in ATPrepCmd, else do it */
if ( recursing )
ATSimplePermissions ( rel , ATT_TABLE ) ;
attrdesc = heap_open ( AttributeRelationId , RowExclusiveLock ) ;
/*
* Are we adding the column to a recursion child ? If so , check whether to
* merge with an existing definition for the column .
* merge with an existing definition for the column . If we do merge ,
* we must not recurse . Children will already have the column , and
* recursing into them would mess up attinhcount .
*/
if ( colDef - > inhcount > 0 )
{
@ -4389,6 +4357,50 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
* Add needed dependency entries for the new column .
*/
add_column_datatype_dependency ( myrelid , newattnum , attribute . atttypid , attribute . attcollation ) ;
/*
* Propagate to children as appropriate . Unlike most other ALTER
* routines , we have to do this one level of recursion at a time ; we can ' t
* use find_all_inheritors to do it in one pass .
*/
children = find_inheritance_children ( RelationGetRelid ( rel ) , lockmode ) ;
/*
* If we are told not to recurse , there had better not be any child
* tables ; else the addition would put them out of step .
*/
if ( children & & ! recurse )
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_TABLE_DEFINITION ) ,
errmsg ( " column must be added to child tables too " ) ) ) ;
/* Children should see column as singly inherited */
if ( ! recursing )
{
colDef = copyObject ( colDef ) ;
colDef - > inhcount = 1 ;
colDef - > is_local = false ;
}
foreach ( child , children )
{
Oid childrelid = lfirst_oid ( child ) ;
Relation childrel ;
AlteredTableInfo * childtab ;
/* find_inheritance_children already got lock */
childrel = heap_open ( childrelid , NoLock ) ;
CheckTableNotInUse ( childrel , " ALTER TABLE " ) ;
/* Find or create work queue entry for this table */
childtab = ATGetQueueEntry ( wqueue , childrel ) ;
/* Recurse to child */
ATExecAddColumn ( wqueue , childtab , childrel ,
colDef , isOid , recurse , true , lockmode ) ;
heap_close ( childrel , NoLock ) ;
}
}
/*
@ -4440,6 +4452,9 @@ ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOC
cmd - > def = ( Node * ) cdef ;
}
ATPrepAddColumn ( wqueue , rel , recurse , false , cmd , lockmode ) ;
if ( recurse )
cmd - > subtype = AT_AddOidsRecurse ;
}
/*