@@ -285,16 +285,15 @@ static void ATSimplePermissions(Relation rel, int allowed_targets);
285
285
static void ATWrongRelkindError (Relation rel , int allowed_targets );
286
286
static void ATSimpleRecursion (List * * wqueue , Relation rel ,
287
287
AlterTableCmd * cmd , bool recurse , LOCKMODE lockmode );
288
- static void ATOneLevelRecursion (List * * wqueue , Relation rel ,
289
- AlterTableCmd * cmd , LOCKMODE lockmode );
290
288
static void ATTypedTableRecursion (List * * wqueue , Relation rel , AlterTableCmd * cmd ,
291
289
LOCKMODE lockmode );
292
290
static List * find_typed_table_dependencies (Oid typeOid , const char * typeName ,
293
291
DropBehavior behavior );
294
292
static void ATPrepAddColumn (List * * wqueue , Relation rel , bool recurse , bool recursing ,
295
293
AlterTableCmd * 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 );
298
297
static void add_column_datatype_dependency (Oid relid , int32 attnum , Oid typid , Oid collid );
299
298
static void ATPrepAddOids (List * * wqueue , Relation rel , bool recurse ,
300
299
AlterTableCmd * cmd , LOCKMODE lockmode );
@@ -2775,15 +2774,15 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
2775
2774
case AT_AddColumn : /* ADD COLUMN */
2776
2775
ATSimplePermissions (rel ,
2777
2776
ATT_TABLE |ATT_COMPOSITE_TYPE |ATT_FOREIGN_TABLE );
2778
- /* Performs own recursion */
2779
2777
ATPrepAddColumn (wqueue , rel , recurse , recursing , cmd , lockmode );
2778
+ /* Recursion occurs during execution phase */
2780
2779
pass = AT_PASS_ADD_COL ;
2781
2780
break ;
2782
2781
case AT_AddColumnToView : /* add column via CREATE OR REPLACE
2783
2782
* VIEW */
2784
2783
ATSimplePermissions (rel , ATT_VIEW );
2785
- /* Performs own recursion */
2786
2784
ATPrepAddColumn (wqueue , rel , recurse , recursing , cmd , lockmode );
2785
+ /* Recursion occurs during execution phase */
2787
2786
pass = AT_PASS_ADD_COL ;
2788
2787
break ;
2789
2788
case AT_ColumnDefault : /* ALTER COLUMN DEFAULT */
@@ -2885,9 +2884,9 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
2885
2884
break ;
2886
2885
case AT_AddOids : /* SET WITH OIDS */
2887
2886
ATSimplePermissions (rel , ATT_TABLE );
2888
- /* Performs own recursion */
2889
2887
if (!rel -> rd_rel -> relhasoids || recursing )
2890
2888
ATPrepAddOids (wqueue , rel , recurse , cmd , lockmode );
2889
+ /* Recursion occurs during execution phase */
2891
2890
pass = AT_PASS_ADD_COL ;
2892
2891
break ;
2893
2892
case AT_DropOids : /* SET WITHOUT OIDS */
@@ -3043,7 +3042,12 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
3043
3042
case AT_AddColumn : /* ADD COLUMN */
3044
3043
case AT_AddColumnToView : /* add column via CREATE OR REPLACE
3045
3044
* 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 );
3047
3051
break ;
3048
3052
case AT_ColumnDefault : /* ALTER COLUMN DEFAULT */
3049
3053
ATExecColumnDefault (rel , cmd -> name , cmd -> def , lockmode );
@@ -3121,7 +3125,14 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
3121
3125
case AT_AddOids : /* SET WITH OIDS */
3122
3126
/* Use the ADD COLUMN code, unless prep decided to do nothing */
3123
3127
if (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 );
3125
3136
break ;
3126
3137
case AT_DropOids : /* SET WITHOUT OIDS */
3127
3138
@@ -3842,37 +3853,6 @@ ATSimpleRecursion(List **wqueue, Relation rel,
3842
3853
}
3843
3854
}
3844
3855
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
-
3876
3856
/*
3877
3857
* ATTypedTableRecursion
3878
3858
*
@@ -4060,6 +4040,12 @@ find_typed_table_dependencies(Oid typeOid, const char *typeName, DropBehavior be
4060
4040
* CHECK, NOT NULL, and FOREIGN KEY constraints will be removed from the
4061
4041
* AT_AddColumn AlterTableCmd by parse_utilcmd.c and added as independent
4062
4042
* 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.)
4063
4049
*/
4064
4050
static void
4065
4051
ATPrepAddColumn (List * * wqueue , Relation rel , bool recurse , bool recursing ,
@@ -4070,43 +4056,17 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
4070
4056
(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
4071
4057
errmsg ("cannot add column to typed table" )));
4072
4058
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
-
4103
4059
if (rel -> rd_rel -> relkind == RELKIND_COMPOSITE_TYPE )
4104
4060
ATTypedTableRecursion (wqueue , rel , cmd , lockmode );
4061
+
4062
+ if (recurse )
4063
+ cmd -> subtype = AT_AddColumnRecurse ;
4105
4064
}
4106
4065
4107
4066
static 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 )
4110
4070
{
4111
4071
Oid myrelid = RelationGetRelid (rel );
4112
4072
Relation pgclass ,
@@ -4121,12 +4081,20 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
4121
4081
Oid collOid ;
4122
4082
Form_pg_type tform ;
4123
4083
Expr * 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 );
4124
4090
4125
4091
attrdesc = heap_open (AttributeRelationId , RowExclusiveLock );
4126
4092
4127
4093
/*
4128
4094
* 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.
4130
4098
*/
4131
4099
if (colDef -> inhcount > 0 )
4132
4100
{
@@ -4389,6 +4357,50 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
4389
4357
* Add needed dependency entries for the new column.
4390
4358
*/
4391
4359
add_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
+ }
4392
4404
}
4393
4405
4394
4406
/*
@@ -4440,6 +4452,9 @@ ATPrepAddOids(List **wqueue, Relation rel, bool recurse, AlterTableCmd *cmd, LOC
4440
4452
cmd -> def = (Node * ) cdef ;
4441
4453
}
4442
4454
ATPrepAddColumn (wqueue , rel , recurse , false, cmd , lockmode );
4455
+
4456
+ if (recurse )
4457
+ cmd -> subtype = AT_AddOidsRecurse ;
4443
4458
}
4444
4459
4445
4460
/*
0 commit comments