@@ -7899,6 +7899,7 @@ ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMOD
7899
7899
Form_pg_attribute attTup;
7900
7900
AttrNumber attnum;
7901
7901
Relation attrelation;
7902
+ Oid attrdefoid;
7902
7903
ObjectAddress address;
7903
7904
7904
7905
attrelation = table_open(AttributeRelationId, RowExclusiveLock);
@@ -7936,71 +7937,44 @@ ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMOD
7936
7937
}
7937
7938
}
7938
7939
7940
+ /*
7941
+ * Mark the column as no longer generated. (The atthasdef flag needs to
7942
+ * get cleared too, but RemoveAttrDefault will handle that.)
7943
+ */
7939
7944
attTup->attgenerated = '\0';
7940
7945
CatalogTupleUpdate(attrelation, &tuple->t_self, tuple);
7941
7946
7942
7947
InvokeObjectPostAlterHook(RelationRelationId,
7943
7948
RelationGetRelid(rel),
7944
- attTup->attnum);
7945
- ObjectAddressSubSet(address, RelationRelationId,
7946
- RelationGetRelid(rel), attnum);
7949
+ attnum);
7947
7950
heap_freetuple(tuple);
7948
7951
7949
7952
table_close(attrelation, RowExclusiveLock);
7950
7953
7951
- CommandCounterIncrement();
7952
-
7953
- RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false, false);
7954
-
7955
7954
/*
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.
7961
7958
*/
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);
7982
7964
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();
8000
7967
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);
8003
7975
7976
+ ObjectAddressSubSet(address, RelationRelationId,
7977
+ RelationGetRelid(rel), attnum);
8004
7978
return address;
8005
7979
}
8006
7980
@@ -12548,21 +12522,6 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
12548
12522
*/
12549
12523
Assert(foundObject.objectSubId == 0);
12550
12524
}
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
- }
12566
12525
else
12567
12526
{
12568
12527
/* Not expecting any other direct dependencies... */
@@ -12625,13 +12584,39 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
12625
12584
break;
12626
12585
12627
12586
case OCLASS_DEFAULT:
12587
+ {
12588
+ ObjectAddress col = GetAttrDefaultColumnAddress(foundObject.objectId);
12628
12589
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
+ }
12635
12620
12636
12621
case OCLASS_STATISTIC_EXT:
12637
12622
@@ -12694,9 +12679,8 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
12694
12679
12695
12680
/*
12696
12681
* 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.
12700
12684
*/
12701
12685
ScanKeyInit(&key[0],
12702
12686
Anum_pg_depend_classid,
@@ -12723,18 +12707,13 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
12723
12707
foundObject.objectId = foundDep->refobjid;
12724
12708
foundObject.objectSubId = foundDep->refobjsubid;
12725
12709
12726
- if (foundDep->deptype != DEPENDENCY_NORMAL &&
12727
- foundDep->deptype != DEPENDENCY_AUTO)
12710
+ if (foundDep->deptype != DEPENDENCY_NORMAL)
12728
12711
elog(ERROR, "found unexpected dependency type '%c'",
12729
12712
foundDep->deptype);
12730
12713
if (!(foundDep->refclassid == TypeRelationId &&
12731
12714
foundDep->refobjid == attTup->atttypid) &&
12732
12715
!(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))
12738
12717
elog(ERROR, "found unexpected dependency for column: %s",
12739
12718
getObjectDescription(&foundObject, false));
12740
12719
@@ -12850,7 +12829,25 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
12850
12829
*/
12851
12830
if (defaultexpr)
12852
12831
{
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
+ */
12854
12851
CommandCounterIncrement();
12855
12852
12856
12853
/*
0 commit comments