@@ -405,6 +405,8 @@ static bool ConstraintImpliedByRelConstraint(Relation scanrel,
405405 List *testConstraint, List *provenConstraint);
406406static ObjectAddress ATExecColumnDefault(Relation rel, const char *colName,
407407 Node *newDefault, LOCKMODE lockmode);
408+ static ObjectAddress ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
409+ Node *newDefault);
408410static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
409411 Node *def, LOCKMODE lockmode);
410412static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
@@ -2054,8 +2056,8 @@ storage_name(char c)
20542056 * 'schema' is the column/attribute definition for the table. (It's a list
20552057 * of ColumnDef's.) It is destructively changed.
20562058 * '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.
20592061 *
20602062 * Output arguments:
20612063 * 'supconstr' receives a list of constraints belonging to the parents,
@@ -2218,7 +2220,11 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
22182220 TupleDesc tupleDesc;
22192221 TupleConstr *constr;
22202222 AttrMap *newattmap;
2223+ List *inherited_defaults;
2224+ List *cols_with_defaults;
22212225 AttrNumber parent_attno;
2226+ ListCell *lc1;
2227+ ListCell *lc2;
22222228
22232229 /* caller already got lock */
22242230 relation = table_open(parent, NoLock);
@@ -2304,6 +2310,9 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
23042310 */
23052311 newattmap = make_attrmap(tupleDesc->natts);
23062312
2313+ /* We can't process inherited defaults until newattmap is complete. */
2314+ inherited_defaults = cols_with_defaults = NIL;
2315+
23072316 for (parent_attno = 1; parent_attno <= tupleDesc->natts;
23082317 parent_attno++)
23092318 {
@@ -2359,7 +2368,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
23592368 get_collation_name(defCollId),
23602369 get_collation_name(attribute->attcollation))));
23612370
2362- /* Copy storage parameter */
2371+ /* Copy/check storage parameter */
23632372 if (def->storage == 0)
23642373 def->storage = attribute->attstorage;
23652374 else if (def->storage != attribute->attstorage)
@@ -2410,7 +2419,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
24102419 }
24112420
24122421 /*
2413- * Copy default if any
2422+ * Locate default if any
24142423 */
24152424 if (attribute->atthasdef)
24162425 {
@@ -2432,23 +2441,59 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
24322441 Assert(this_default != NULL);
24332442
24342443 /*
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.
24432448 */
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;
24522497 }
24532498 }
24542499
@@ -2667,7 +2712,6 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
26672712 def->raw_default = newdef->raw_default;
26682713 def->cooked_default = newdef->cooked_default;
26692714 }
2670-
26712715 }
26722716 else
26732717 {
@@ -3781,6 +3825,7 @@ AlterTableGetLockLevel(List *cmds)
37813825 * Theoretically, these could be ShareRowExclusiveLock.
37823826 */
37833827 case AT_ColumnDefault:
3828+ case AT_CookedColumnDefault:
37843829 case AT_AlterConstraint:
37853830 case AT_AddIndex: /* from ADD CONSTRAINT */
37863831 case AT_AddIndexConstraint:
@@ -4040,6 +4085,13 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
40404085 /* No command-specific prep needed */
40414086 pass = cmd->def ? AT_PASS_ADD_OTHERCONSTR : AT_PASS_DROP;
40424087 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;
40434095 case AT_AddIdentity:
40444096 ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE);
40454097 /* This command never recurses */
@@ -4398,6 +4450,9 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
43984450 case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
43994451 address = ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
44004452 break;
4453+ case AT_CookedColumnDefault: /* add a pre-cooked default */
4454+ address = ATExecCookedColumnDefault(rel, cmd->num, cmd->def);
4455+ break;
44014456 case AT_AddIdentity:
44024457 cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
44034458 cur_pass, context);
@@ -6859,6 +6914,35 @@ ATExecColumnDefault(Relation rel, const char *colName,
68596914 return address;
68606915}
68616916
6917+ /*
6918+ * Add a pre-cooked default expression.
6919+ *
6920+ * Return the address of the affected column.
6921+ */
6922+ static ObjectAddress
6923+ ATExecCookedColumnDefault(Relation rel, AttrNumber attnum,
6924+ Node *newDefault)
6925+ {
6926+ ObjectAddress address;
6927+
6928+ /* We assume no checking is required */
6929+
6930+ /*
6931+ * Remove any old default for the column. We use RESTRICT here for
6932+ * safety, but at present we do not expect anything to depend on the
6933+ * default. (In ordinary cases, there could not be a default in place
6934+ * anyway, but it's possible when combining LIKE with inheritance.)
6935+ */
6936+ RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false,
6937+ true);
6938+
6939+ (void) StoreAttrDefault(rel, attnum, newDefault, true, false);
6940+
6941+ ObjectAddressSubSet(address, RelationRelationId,
6942+ RelationGetRelid(rel), attnum);
6943+ return address;
6944+ }
6945+
68626946/*
68636947 * ALTER TABLE ALTER COLUMN ADD IDENTITY
68646948 *
0 commit comments