@@ -285,16 +285,15 @@ static void ATSimplePermissions(Relation rel, int allowed_targets);
285285static void ATWrongRelkindError (Relation rel ,int allowed_targets );
286286static void ATSimpleRecursion (List * * wqueue ,Relation rel ,
287287AlterTableCmd * cmd ,bool recurse ,LOCKMODE lockmode );
288- static void ATOneLevelRecursion (List * * wqueue ,Relation rel ,
289- AlterTableCmd * cmd ,LOCKMODE lockmode );
290288static void ATTypedTableRecursion (List * * wqueue ,Relation rel ,AlterTableCmd * cmd ,
291289LOCKMODE lockmode );
292290static List * find_typed_table_dependencies (Oid typeOid ,const char * typeName ,
293291DropBehavior behavior );
294292static void ATPrepAddColumn (List * * wqueue ,Relation rel ,bool recurse ,bool recursing ,
295293AlterTableCmd * cmd ,LOCKMODE lockmode );
296- static void ATExecAddColumn (AlteredTableInfo * tab ,Relation rel ,
297- ColumnDef * colDef ,bool isOid ,LOCKMODE lockmode );
294+ static void ATExecAddColumn (List * * wqueue ,AlteredTableInfo * tab ,Relation rel ,
295+ ColumnDef * colDef ,bool isOid ,
296+ bool recurse ,bool recursing ,LOCKMODE lockmode );
298297static void add_column_datatype_dependency (Oid relid ,int32 attnum ,Oid typid ,Oid collid );
299298static void ATPrepAddOids (List * * wqueue ,Relation rel ,bool recurse ,
300299AlterTableCmd * cmd ,LOCKMODE lockmode );
@@ -2775,15 +2774,15 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
27752774case AT_AddColumn :/* ADD COLUMN */
27762775ATSimplePermissions (rel ,
27772776ATT_TABLE |ATT_COMPOSITE_TYPE |ATT_FOREIGN_TABLE );
2778- /* Performs own recursion */
27792777ATPrepAddColumn (wqueue ,rel ,recurse ,recursing ,cmd ,lockmode );
2778+ /* Recursion occurs during execution phase */
27802779pass = AT_PASS_ADD_COL ;
27812780break ;
27822781case AT_AddColumnToView :/* add column via CREATE OR REPLACE
27832782 * VIEW */
27842783ATSimplePermissions (rel ,ATT_VIEW );
2785- /* Performs own recursion */
27862784ATPrepAddColumn (wqueue ,rel ,recurse ,recursing ,cmd ,lockmode );
2785+ /* Recursion occurs during execution phase */
27872786pass = AT_PASS_ADD_COL ;
27882787break ;
27892788case AT_ColumnDefault :/* ALTER COLUMN DEFAULT */
@@ -2885,9 +2884,9 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
28852884break ;
28862885case AT_AddOids :/* SET WITH OIDS */
28872886ATSimplePermissions (rel ,ATT_TABLE );
2888- /* Performs own recursion */
28892887if (!rel -> rd_rel -> relhasoids || recursing )
28902888ATPrepAddOids (wqueue ,rel ,recurse ,cmd ,lockmode );
2889+ /* Recursion occurs during execution phase */
28912890pass = AT_PASS_ADD_COL ;
28922891break ;
28932892case AT_DropOids :/* SET WITHOUT OIDS */
@@ -3043,7 +3042,12 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
30433042case AT_AddColumn :/* ADD COLUMN */
30443043case AT_AddColumnToView :/* add column via CREATE OR REPLACE
30453044 * VIEW */
3046- ATExecAddColumn (tab ,rel , (ColumnDef * )cmd -> def , false,lockmode );
3045+ ATExecAddColumn (wqueue ,tab ,rel , (ColumnDef * )cmd -> def ,
3046+ false, false, false,lockmode );
3047+ break ;
3048+ case AT_AddColumnRecurse :
3049+ ATExecAddColumn (wqueue ,tab ,rel , (ColumnDef * )cmd -> def ,
3050+ false, true, false,lockmode );
30473051break ;
30483052case AT_ColumnDefault :/* ALTER COLUMN DEFAULT */
30493053ATExecColumnDefault (rel ,cmd -> name ,cmd -> def ,lockmode );
@@ -3121,7 +3125,14 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
31213125case AT_AddOids :/* SET WITH OIDS */
31223126/* Use the ADD COLUMN code, unless prep decided to do nothing */
31233127if (cmd -> def != NULL )
3124- ATExecAddColumn (tab ,rel , (ColumnDef * )cmd -> def , true,lockmode );
3128+ ATExecAddColumn (wqueue ,tab ,rel , (ColumnDef * )cmd -> def ,
3129+ true, false, false,lockmode );
3130+ break ;
3131+ case AT_AddOidsRecurse :/* SET WITH OIDS */
3132+ /* Use the ADD COLUMN code, unless prep decided to do nothing */
3133+ if (cmd -> def != NULL )
3134+ ATExecAddColumn (wqueue ,tab ,rel , (ColumnDef * )cmd -> def ,
3135+ true, true, false,lockmode );
31253136break ;
31263137case AT_DropOids :/* SET WITHOUT OIDS */
31273138
@@ -3842,37 +3853,6 @@ ATSimpleRecursion(List **wqueue, Relation rel,
38423853}
38433854}
38443855
3845- /*
3846- * ATOneLevelRecursion
3847- *
3848- * Here, we visit only direct inheritance children. It is expected that
3849- * the command's prep routine will recurse again to find indirect children.
3850- * When using this technique, a multiply-inheriting child will be visited
3851- * multiple times.
3852- */
3853- static void
3854- ATOneLevelRecursion (List * * wqueue ,Relation rel ,
3855- AlterTableCmd * cmd ,LOCKMODE lockmode )
3856- {
3857- Oid relid = RelationGetRelid (rel );
3858- ListCell * child ;
3859- List * children ;
3860-
3861- children = find_inheritance_children (relid ,lockmode );
3862-
3863- foreach (child ,children )
3864- {
3865- Oid childrelid = lfirst_oid (child );
3866- Relation childrel ;
3867-
3868- /* find_inheritance_children already got lock */
3869- childrel = relation_open (childrelid ,NoLock );
3870- CheckTableNotInUse (childrel ,"ALTER TABLE" );
3871- ATPrepCmd (wqueue ,childrel ,cmd , true, true,lockmode );
3872- relation_close (childrel ,NoLock );
3873- }
3874- }
3875-
38763856/*
38773857 * ATTypedTableRecursion
38783858 *
@@ -4060,6 +4040,12 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior be
40604040 * CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
40614041 * AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
40624042 * AlterTableCmd's.
4043+ *
4044+ * ADD COLUMN cannot use the normal ALTER TABLE recursion mechanism, because we
4045+ * have to decide at runtime whether to recurse or not depending on whether we
4046+ * actually add a column or merely merge with an existing column. (We can't
4047+ * check this in a static pre-pass because it won't handle multiple inheritance
4048+ * situations correctly.)
40634049 */
40644050static void
40654051ATPrepAddColumn (List * * wqueue ,Relation rel ,bool recurse ,bool recursing ,
@@ -4070,43 +4056,17 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
40704056(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
40714057errmsg ("cannot add column to typed table" )));
40724058
4073- /*
4074- * Recurse to add the column to child classes, if requested.
4075- *
4076- * We must recurse one level at a time, so that multiply-inheriting
4077- * children are visited the right number of times and end up with the
4078- * right attinhcount.
4079- */
4080- if (recurse )
4081- {
4082- AlterTableCmd * childCmd = copyObject (cmd );
4083- ColumnDef * colDefChild = (ColumnDef * )childCmd -> def ;
4084-
4085- /* Child should see column as singly inherited */
4086- colDefChild -> inhcount = 1 ;
4087- colDefChild -> is_local = false;
4088-
4089- ATOneLevelRecursion (wqueue ,rel ,childCmd ,lockmode );
4090- }
4091- else
4092- {
4093- /*
4094- * If we are told not to recurse, there had better not be any child
4095- * tables; else the addition would put them out of step.
4096- */
4097- if (find_inheritance_children (RelationGetRelid (rel ),NoLock )!= NIL )
4098- ereport (ERROR ,
4099- (errcode (ERRCODE_INVALID_TABLE_DEFINITION ),
4100- errmsg ("column must be added to child tables too" )));
4101- }
4102-
41034059if (rel -> rd_rel -> relkind == RELKIND_COMPOSITE_TYPE )
41044060ATTypedTableRecursion (wqueue ,rel ,cmd ,lockmode );
4061+
4062+ if (recurse )
4063+ cmd -> subtype = AT_AddColumnRecurse ;
41054064}
41064065
41074066static void
4108- ATExecAddColumn (AlteredTableInfo * tab ,Relation rel ,
4109- ColumnDef * colDef ,bool isOid ,LOCKMODE lockmode )
4067+ ATExecAddColumn (List * * wqueue ,AlteredTableInfo * tab ,Relation rel ,
4068+ ColumnDef * colDef ,bool isOid ,
4069+ bool recurse ,bool recursing ,LOCKMODE lockmode )
41104070{
41114071Oid myrelid = RelationGetRelid (rel );
41124072Relation pgclass ,
@@ -4121,12 +4081,20 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
41214081Oid collOid ;
41224082Form_pg_type tform ;
41234083Expr * defval ;
4084+ List * children ;
4085+ ListCell * child ;
4086+
4087+ /* At top level, permission check was done in ATPrepCmd, else do it */
4088+ if (recursing )
4089+ ATSimplePermissions (rel ,ATT_TABLE );
41244090
41254091attrdesc = heap_open (AttributeRelationId ,RowExclusiveLock );
41264092
41274093/*
41284094 * Are we adding the column to a recursion child? If so, check whether to
4129- * merge with an existing definition for the column.
4095+ * merge with an existing definition for the column. If we do merge,
4096+ * we must not recurse. Children will already have the column, and
4097+ * recursing into them would mess up attinhcount.
41304098 */
41314099if (colDef -> inhcount > 0 )
41324100{
@@ -4389,6 +4357,50 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
43894357 * Add needed dependency entries for the new column.
43904358 */
43914359add_column_datatype_dependency (myrelid ,newattnum ,attribute .atttypid ,attribute .attcollation );
4360+
4361+ /*
4362+ * Propagate to children as appropriate. Unlike most other ALTER
4363+ * routines, we have to do this one level of recursion at a time; we can't
4364+ * use find_all_inheritors to do it in one pass.
4365+ */
4366+ children = find_inheritance_children (RelationGetRelid (rel ),lockmode );
4367+
4368+ /*
4369+ * If we are told not to recurse, there had better not be any child
4370+ * tables; else the addition would put them out of step.
4371+ */
4372+ if (children && !recurse )
4373+ ereport (ERROR ,
4374+ (errcode (ERRCODE_INVALID_TABLE_DEFINITION ),
4375+ errmsg ("column must be added to child tables too" )));
4376+
4377+ /* Children should see column as singly inherited */
4378+ if (!recursing )
4379+ {
4380+ colDef = copyObject (colDef );
4381+ colDef -> inhcount = 1 ;
4382+ colDef -> is_local = false;
4383+ }
4384+
4385+ foreach (child ,children )
4386+ {
4387+ Oid childrelid = lfirst_oid (child );
4388+ Relation childrel ;
4389+ AlteredTableInfo * childtab ;
4390+
4391+ /* find_inheritance_children already got lock */
4392+ childrel = heap_open (childrelid ,NoLock );
4393+ CheckTableNotInUse (childrel ,"ALTER TABLE" );
4394+
4395+ /* Find or create work queue entry for this table */
4396+ childtab = ATGetQueueEntry (wqueue ,childrel );
4397+
4398+ /* Recurse to child */
4399+ ATExecAddColumn (wqueue ,childtab ,childrel ,
4400+ colDef ,isOid ,recurse , true,lockmode );
4401+
4402+ heap_close (childrel ,NoLock );
4403+ }
43924404}
43934405
43944406/*
@@ -4440,6 +4452,9 @@ ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOC
44404452cmd -> def = (Node * )cdef ;
44414453}
44424454ATPrepAddColumn (wqueue ,rel ,recurse , false,cmd ,lockmode );
4455+
4456+ if (recurse )
4457+ cmd -> subtype = AT_AddOidsRecurse ;
44434458}
44444459
44454460/*