@@ -405,6 +405,8 @@ static bool ConstraintImpliedByRelConstraint(Relation scanrel,
405
405
List *testConstraint, List *provenConstraint);
406
406
static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
407
407
Node *newDefault, LOCKMODE lockmode);
408
+ static ObjectAddress ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
409
+ Node *newDefault);
408
410
static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
409
411
Node *def, LOCKMODE lockmode);
410
412
static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
@@ -2054,8 +2056,8 @@ storage_name(char c)
2054
2056
* 'schema' is the column/attribute definition for the table. (It's a list
2055
2057
* of ColumnDef's.) It is destructively changed.
2056
2058
* 'supers' is a list of OIDs of parent relations, already locked by caller.
2057
- * 'relpersistence' is a persistence type of the table.
2058
- * 'is_partition' tells if the table is a partition
2059
+ * 'relpersistence' is the persistence type of the table.
2060
+ * 'is_partition' tells if the table is a partition.
2059
2061
*
2060
2062
* Output arguments:
2061
2063
* 'supconstr' receives a list of constraints belonging to the parents,
@@ -2218,7 +2220,11 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
2218
2220
TupleDesc tupleDesc;
2219
2221
TupleConstr *constr;
2220
2222
AttrMap *newattmap;
2223
+ List *inherited_defaults;
2224
+ List *cols_with_defaults;
2221
2225
AttrNumber parent_attno;
2226
+ ListCell *lc1;
2227
+ ListCell *lc2;
2222
2228
2223
2229
/* caller already got lock */
2224
2230
relation = table_open(parent, NoLock);
@@ -2304,6 +2310,9 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
2304
2310
*/
2305
2311
newattmap = make_attrmap(tupleDesc->natts);
2306
2312
2313
+ /* We can't process inherited defaults until newattmap is complete. */
2314
+ inherited_defaults = cols_with_defaults = NIL;
2315
+
2307
2316
for (parent_attno = 1; parent_attno <= tupleDesc->natts;
2308
2317
parent_attno++)
2309
2318
{
@@ -2359,7 +2368,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
2359
2368
get_collation_name(defCollId),
2360
2369
get_collation_name(attribute->attcollation))));
2361
2370
2362
- /* Copy storage parameter */
2371
+ /* Copy/check storage parameter */
2363
2372
if (def->storage == 0)
2364
2373
def->storage = attribute->attstorage;
2365
2374
else if (def->storage != attribute->attstorage)
@@ -2410,7 +2419,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
2410
2419
}
2411
2420
2412
2421
/*
2413
- * Copy default if any
2422
+ * Locate default if any
2414
2423
*/
2415
2424
if (attribute->atthasdef)
2416
2425
{
@@ -2432,23 +2441,59 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
2432
2441
Assert(this_default != NULL);
2433
2442
2434
2443
/*
2435
- * If default expr could contain any vars, we'd need to fix
2436
- * 'em, but it can't; so default is ready to apply to child.
2437
- *
2438
- * If we already had a default from some prior parent, check
2439
- * to see if they are the same. If so, no problem; if not,
2440
- * mark the column as having a bogus default. Below, we will
2441
- * complain if the bogus default isn't overridden by the child
2442
- * schema.
2444
+ * If it's a GENERATED default, it might contain Vars that
2445
+ * need to be mapped to the inherited column(s)' new numbers.
2446
+ * We can't do that till newattmap is ready, so just remember
2447
+ * all the inherited default expressions for the moment.
2443
2448
*/
2444
- Assert(def->raw_default == NULL);
2445
- if (def->cooked_default == NULL)
2446
- def->cooked_default = this_default;
2447
- else if (!equal(def->cooked_default, this_default))
2448
- {
2449
- def->cooked_default = &bogus_marker;
2450
- have_bogus_defaults = true;
2451
- }
2449
+ inherited_defaults = lappend(inherited_defaults, this_default);
2450
+ cols_with_defaults = lappend(cols_with_defaults, def);
2451
+ }
2452
+ }
2453
+
2454
+ /*
2455
+ * Now process any inherited default expressions, adjusting attnos
2456
+ * using the completed newattmap map.
2457
+ */
2458
+ forboth(lc1, inherited_defaults, lc2, cols_with_defaults)
2459
+ {
2460
+ Node *this_default = (Node *) lfirst(lc1);
2461
+ ColumnDef *def = (ColumnDef *) lfirst(lc2);
2462
+ bool found_whole_row;
2463
+
2464
+ /* Adjust Vars to match new table's column numbering */
2465
+ this_default = map_variable_attnos(this_default,
2466
+ 1, 0,
2467
+ newattmap,
2468
+ InvalidOid, &found_whole_row);
2469
+
2470
+ /*
2471
+ * For the moment we have to reject whole-row variables. We could
2472
+ * convert them, if we knew the new table's rowtype OID, but that
2473
+ * hasn't been assigned yet. (A variable could only appear in a
2474
+ * generation expression, so the error message is correct.)
2475
+ */
2476
+ if (found_whole_row)
2477
+ ereport(ERROR,
2478
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2479
+ errmsg("cannot convert whole-row table reference"),
2480
+ errdetail("Generation expression for column \"%s\" contains a whole-row reference to table \"%s\".",
2481
+ def->colname,
2482
+ RelationGetRelationName(relation))));
2483
+
2484
+ /*
2485
+ * If we already had a default from some prior parent, check to
2486
+ * see if they are the same. If so, no problem; if not, mark the
2487
+ * column as having a bogus default. Below, we will complain if
2488
+ * the bogus default isn't overridden by the child schema.
2489
+ */
2490
+ Assert(def->raw_default == NULL);
2491
+ if (def->cooked_default == NULL)
2492
+ def->cooked_default = this_default;
2493
+ else if (!equal(def->cooked_default, this_default))
2494
+ {
2495
+ def->cooked_default = &bogus_marker;
2496
+ have_bogus_defaults = true;
2452
2497
}
2453
2498
}
2454
2499
@@ -2667,7 +2712,6 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
2667
2712
def->raw_default = newdef->raw_default;
2668
2713
def->cooked_default = newdef->cooked_default;
2669
2714
}
2670
-
2671
2715
}
2672
2716
else
2673
2717
{
@@ -3781,6 +3825,7 @@ AlterTableGetLockLevel(List *cmds)
3781
3825
* Theoretically, these could be ShareRowExclusiveLock.
3782
3826
*/
3783
3827
case AT_ColumnDefault:
3828
+ case AT_CookedColumnDefault:
3784
3829
case AT_AlterConstraint:
3785
3830
case AT_AddIndex: /* from ADD CONSTRAINT */
3786
3831
case AT_AddIndexConstraint:
@@ -4040,6 +4085,13 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
4040
4085
/* No command-specific prep needed */
4041
4086
pass = cmd->def ? AT_PASS_ADD_OTHERCONSTR : AT_PASS_DROP;
4042
4087
break;
4088
+ case AT_CookedColumnDefault: /* add a pre-cooked default */
4089
+ /* This is currently used only in CREATE TABLE */
4090
+ /* (so the permission check really isn't necessary) */
4091
+ ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
4092
+ /* This command never recurses */
4093
+ pass = AT_PASS_ADD_OTHERCONSTR;
4094
+ break;
4043
4095
case AT_AddIdentity:
4044
4096
ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
4045
4097
/* This command never recurses */
@@ -4398,6 +4450,9 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
4398
4450
case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
4399
4451
address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
4400
4452
break;
4453
+ case AT_CookedColumnDefault: /* add a pre-cooked default */
4454
+ address = ATExecCookedColumnDefault(rel, cmd->num, cmd->def);
4455
+ break;
4401
4456
case AT_AddIdentity:
4402
4457
cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
4403
4458
cur_pass, context);
@@ -6857,6 +6912,35 @@ ATExecColumnDefault(Relation rel, const char *colName,
6857
6912
return address;
6858
6913
}
6859
6914
6915
+ /*
6916
+ * Add a pre-cooked default expression.
6917
+ *
6918
+ * Return the address of the affected column.
6919
+ */
6920
+ static ObjectAddress
6921
+ ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
6922
+ Node *newDefault)
6923
+ {
6924
+ ObjectAddress address;
6925
+
6926
+ /* We assume no checking is required */
6927
+
6928
+ /*
6929
+ * Remove any old default for the column. We use RESTRICT here for
6930
+ * safety, but at present we do not expect anything to depend on the
6931
+ * default. (In ordinary cases, there could not be a default in place
6932
+ * anyway, but it's possible when combining LIKE with inheritance.)
6933
+ */
6934
+ RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
6935
+ true);
6936
+
6937
+ (void) StoreAttrDefault(rel, attnum, newDefault, true, false);
6938
+
6939
+ ObjectAddressSubSet(address, RelationRelationId,
6940
+ RelationGetRelid(rel), attnum);
6941
+ return address;
6942
+ }
6943
+
6860
6944
/*
6861
6945
* ALTER TABLE ALTER COLUMN ADD IDENTITY
6862
6946
*
0 commit comments