@@ -7899,6 +7899,7 @@ ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMOD
78997899 Form_pg_attribute attTup;
79007900 AttrNumber attnum;
79017901 Relation attrelation;
7902+ Oid attrdefoid;
79027903 ObjectAddress address;
79037904
79047905 attrelation = table_open(AttributeRelationId, RowExclusiveLock);
@@ -7936,71 +7937,44 @@ ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMOD
79367937 }
79377938 }
79387939
7940+ /*
7941+ * Mark the column as no longer generated. (The atthasdef flag needs to
7942+ * get cleared too, but RemoveAttrDefault will handle that.)
7943+ */
79397944 attTup->attgenerated = '\0';
79407945 CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
79417946
79427947 InvokeObjectPostAlterHook(RelationRelationId,
79437948 RelationGetRelid(rel),
7944- attTup->attnum);
7945- ObjectAddressSubSet(address, RelationRelationId,
7946- RelationGetRelid(rel), attnum);
7949+ attnum);
79477950 heap_freetuple(tuple);
79487951
79497952 table_close(attrelation, RowExclusiveLock);
79507953
7951- CommandCounterIncrement();
7952-
7953- RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false, false);
7954-
79557954 /*
7956- * Remove all dependencies of this (formerly generated) column on other
7957- * columns in the same table. (See StoreAttrDefault() for which
7958- * dependencies are created.) We don't expect there to be dependencies
7959- * between columns of the same table for other reasons, so it's okay to
7960- * remove all of them.
7955+ * Drop the dependency records of the GENERATED expression, in particular
7956+ * its INTERNAL dependency on the column, which would otherwise cause
7957+ * dependency.c to refuse to perform the deletion.
79617958 */
7962- {
7963- Relation depRel;
7964- ScanKeyData key[3];
7965- SysScanDesc scan;
7966- HeapTuple tup;
7967-
7968- depRel = table_open(DependRelationId, RowExclusiveLock);
7969-
7970- ScanKeyInit(&key[0],
7971- Anum_pg_depend_classid,
7972- BTEqualStrategyNumber, F_OIDEQ,
7973- ObjectIdGetDatum(RelationRelationId));
7974- ScanKeyInit(&key[1],
7975- Anum_pg_depend_objid,
7976- BTEqualStrategyNumber, F_OIDEQ,
7977- ObjectIdGetDatum(RelationGetRelid(rel)));
7978- ScanKeyInit(&key[2],
7979- Anum_pg_depend_objsubid,
7980- BTEqualStrategyNumber, F_INT4EQ,
7981- Int32GetDatum(attnum));
7959+ attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
7960+ if (!OidIsValid(attrdefoid))
7961+ elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
7962+ RelationGetRelid(rel), attnum);
7963+ (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
79827964
7983- scan = systable_beginscan(depRel, DependDependerIndexId, true,
7984- NULL, 3, key);
7985-
7986- while (HeapTupleIsValid(tup = systable_getnext(scan)))
7987- {
7988- Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
7989-
7990- if (depform->refclassid == RelationRelationId &&
7991- depform->refobjid == RelationGetRelid(rel) &&
7992- depform->refobjsubid != 0 &&
7993- depform->deptype == DEPENDENCY_AUTO)
7994- {
7995- CatalogTupleDelete(depRel, &tup->t_self);
7996- }
7997- }
7998-
7999- systable_endscan(scan);
7965+ /* Make above changes visible */
7966+ CommandCounterIncrement();
80007967
8001- table_close(depRel, RowExclusiveLock);
8002- }
7968+ /*
7969+ * Get rid of the GENERATED expression itself. We use RESTRICT here for
7970+ * safety, but at present we do not expect anything to depend on the
7971+ * default.
7972+ */
7973+ RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT,
7974+ false, false);
80037975
7976+ ObjectAddressSubSet(address, RelationRelationId,
7977+ RelationGetRelid(rel), attnum);
80047978 return address;
80057979}
80067980
@@ -12548,21 +12522,6 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
1254812522 */
1254912523 Assert(foundObject.objectSubId == 0);
1255012524 }
12551- else if (relKind == RELKIND_RELATION &&
12552- foundObject.objectSubId != 0 &&
12553- get_attgenerated(foundObject.objectId, foundObject.objectSubId))
12554- {
12555- /*
12556- * Changing the type of a column that is used by a
12557- * generated column is not allowed by SQL standard. It
12558- * might be doable with some thinking and effort.
12559- */
12560- ereport(ERROR,
12561- (errcode(ERRCODE_SYNTAX_ERROR),
12562- errmsg("cannot alter type of a column used by a generated column"),
12563- errdetail("Column \"%s\" is used by generated column \"%s\".",
12564- colName, get_attname(foundObject.objectId, foundObject.objectSubId, false))));
12565- }
1256612525 else
1256712526 {
1256812527 /* Not expecting any other direct dependencies... */
@@ -12625,13 +12584,39 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
1262512584 break;
1262612585
1262712586 case OCLASS_DEFAULT:
12587+ {
12588+ ObjectAddress col = GetAttrDefaultColumnAddress(foundObject.objectId);
1262812589
12629- /*
12630- * Ignore the column's default expression, since we will fix
12631- * it below.
12632- */
12633- Assert(defaultexpr);
12634- break;
12590+ if (col.objectId == RelationGetRelid(rel) &&
12591+ col.objectSubId == attnum)
12592+ {
12593+ /*
12594+ * Ignore the column's own default expression, which
12595+ * we will deal with below.
12596+ */
12597+ Assert(defaultexpr);
12598+ }
12599+ else
12600+ {
12601+ /*
12602+ * This must be a reference from the expression of a
12603+ * generated column elsewhere in the same table.
12604+ * Changing the type of a column that is used by a
12605+ * generated column is not allowed by SQL standard, so
12606+ * just punt for now. It might be doable with some
12607+ * thinking and effort.
12608+ */
12609+ ereport(ERROR,
12610+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
12611+ errmsg("cannot alter type of a column used by a generated column"),
12612+ errdetail("Column \"%s\" is used by generated column \"%s\".",
12613+ colName,
12614+ get_attname(col.objectId,
12615+ col.objectSubId,
12616+ false))));
12617+ }
12618+ break;
12619+ }
1263512620
1263612621 case OCLASS_STATISTIC_EXT:
1263712622
@@ -12694,9 +12679,8 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
1269412679
1269512680 /*
1269612681 * Now scan for dependencies of this column on other things. The only
12697- * thing we should find is the dependency on the column datatype, which we
12698- * want to remove, possibly a collation dependency, and dependencies on
12699- * other columns if it is a generated column.
12682+ * things we should find are the dependency on the column datatype and
12683+ * possibly a collation dependency. Those can be removed.
1270012684 */
1270112685 ScanKeyInit(&key[0],
1270212686 Anum_pg_depend_classid,
@@ -12723,18 +12707,13 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
1272312707 foundObject.objectId = foundDep->refobjid;
1272412708 foundObject.objectSubId = foundDep->refobjsubid;
1272512709
12726- if (foundDep->deptype != DEPENDENCY_NORMAL &&
12727- foundDep->deptype != DEPENDENCY_AUTO)
12710+ if (foundDep->deptype != DEPENDENCY_NORMAL)
1272812711 elog(ERROR, "found unexpected dependency type '%c'",
1272912712 foundDep->deptype);
1273012713 if (!(foundDep->refclassid == TypeRelationId &&
1273112714 foundDep->refobjid == attTup->atttypid) &&
1273212715 !(foundDep->refclassid == CollationRelationId &&
12733- foundDep->refobjid == attTup->attcollation) &&
12734- !(foundDep->refclassid == RelationRelationId &&
12735- foundDep->refobjid == RelationGetRelid(rel) &&
12736- foundDep->refobjsubid != 0)
12737- )
12716+ foundDep->refobjid == attTup->attcollation))
1273812717 elog(ERROR, "found unexpected dependency for column: %s",
1273912718 getObjectDescription(&foundObject, false));
1274012719
@@ -12850,7 +12829,25 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
1285012829 */
1285112830 if (defaultexpr)
1285212831 {
12853- /* Must make new row visible since it will be updated again */
12832+ /*
12833+ * If it's a GENERATED default, drop its dependency records, in
12834+ * particular its INTERNAL dependency on the column, which would
12835+ * otherwise cause dependency.c to refuse to perform the deletion.
12836+ */
12837+ if (attTup->attgenerated)
12838+ {
12839+ Oid attrdefoid = GetAttrDefaultOid(RelationGetRelid(rel), attnum);
12840+
12841+ if (!OidIsValid(attrdefoid))
12842+ elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
12843+ RelationGetRelid(rel), attnum);
12844+ (void) deleteDependencyRecordsFor(AttrDefaultRelationId, attrdefoid, false);
12845+ }
12846+
12847+ /*
12848+ * Make updates-so-far visible, particularly the new pg_attribute row
12849+ * which will be updated again.
12850+ */
1285412851 CommandCounterIncrement();
1285512852
1285612853 /*
0 commit comments