@@ -458,8 +458,6 @@ static ObjectAddress ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
458458 AlterTableCmd *cmd, LOCKMODE lockmode);
459459static void RememberConstraintForRebuilding(Oid conoid, AlteredTableInfo *tab);
460460static void RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab);
461- static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
462- List *options, LOCKMODE lockmode);
463461static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab,
464462 LOCKMODE lockmode);
465463static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId,
@@ -470,6 +468,8 @@ static void RebuildConstraintComment(AlteredTableInfo *tab, int pass,
470468 const char *conname);
471469static void TryReuseIndex(Oid oldId, IndexStmt *stmt);
472470static void TryReuseForeignKey(Oid oldId, Constraint *con);
471+ static ObjectAddress ATExecAlterColumnGenericOptions(Relation rel, const char *colName,
472+ List *options, LOCKMODE lockmode);
473473static void change_owner_fix_column_acls(Oid relationOid,
474474 Oid oldOwnerId, Oid newOwnerId);
475475static void change_owner_recurse_to_sequences(Oid relationOid,
@@ -11048,118 +11048,12 @@ RememberIndexForRebuilding(Oid indoid, AlteredTableInfo *tab)
1104811048 }
1104911049}
1105011050
11051- /*
11052- * Returns the address of the modified column
11053- */
11054- static ObjectAddress
11055- ATExecAlterColumnGenericOptions(Relation rel,
11056- const char *colName,
11057- List *options,
11058- LOCKMODE lockmode)
11059- {
11060- Relation ftrel;
11061- Relation attrel;
11062- ForeignServer *server;
11063- ForeignDataWrapper *fdw;
11064- HeapTuple tuple;
11065- HeapTuple newtuple;
11066- bool isnull;
11067- Datum repl_val[Natts_pg_attribute];
11068- bool repl_null[Natts_pg_attribute];
11069- bool repl_repl[Natts_pg_attribute];
11070- Datum datum;
11071- Form_pg_foreign_table fttableform;
11072- Form_pg_attribute atttableform;
11073- AttrNumber attnum;
11074- ObjectAddress address;
11075-
11076- if (options == NIL)
11077- return InvalidObjectAddress;
11078-
11079- /* First, determine FDW validator associated to the foreign table. */
11080- ftrel = table_open(ForeignTableRelationId, AccessShareLock);
11081- tuple = SearchSysCache1(FOREIGNTABLEREL, rel->rd_id);
11082- if (!HeapTupleIsValid(tuple))
11083- ereport(ERROR,
11084- (errcode(ERRCODE_UNDEFINED_OBJECT),
11085- errmsg("foreign table \"%s\" does not exist",
11086- RelationGetRelationName(rel))));
11087- fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
11088- server = GetForeignServer(fttableform->ftserver);
11089- fdw = GetForeignDataWrapper(server->fdwid);
11090-
11091- table_close(ftrel, AccessShareLock);
11092- ReleaseSysCache(tuple);
11093-
11094- attrel = table_open(AttributeRelationId, RowExclusiveLock);
11095- tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
11096- if (!HeapTupleIsValid(tuple))
11097- ereport(ERROR,
11098- (errcode(ERRCODE_UNDEFINED_COLUMN),
11099- errmsg("column \"%s\" of relation \"%s\" does not exist",
11100- colName, RelationGetRelationName(rel))));
11101-
11102- /* Prevent them from altering a system attribute */
11103- atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
11104- attnum = atttableform->attnum;
11105- if (attnum <= 0)
11106- ereport(ERROR,
11107- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11108- errmsg("cannot alter system column \"%s\"", colName)));
11109-
11110-
11111- /* Initialize buffers for new tuple values */
11112- memset(repl_val, 0, sizeof(repl_val));
11113- memset(repl_null, false, sizeof(repl_null));
11114- memset(repl_repl, false, sizeof(repl_repl));
11115-
11116- /* Extract the current options */
11117- datum = SysCacheGetAttr(ATTNAME,
11118- tuple,
11119- Anum_pg_attribute_attfdwoptions,
11120- &isnull);
11121- if (isnull)
11122- datum = PointerGetDatum(NULL);
11123-
11124- /* Transform the options */
11125- datum = transformGenericOptions(AttributeRelationId,
11126- datum,
11127- options,
11128- fdw->fdwvalidator);
11129-
11130- if (PointerIsValid(DatumGetPointer(datum)))
11131- repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
11132- else
11133- repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
11134-
11135- repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
11136-
11137- /* Everything looks good - update the tuple */
11138-
11139- newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
11140- repl_val, repl_null, repl_repl);
11141-
11142- CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple);
11143-
11144- InvokeObjectPostAlterHook(RelationRelationId,
11145- RelationGetRelid(rel),
11146- atttableform->attnum);
11147- ObjectAddressSubSet(address, RelationRelationId,
11148- RelationGetRelid(rel), attnum);
11149-
11150- ReleaseSysCache(tuple);
11151-
11152- table_close(attrel, RowExclusiveLock);
11153-
11154- heap_freetuple(newtuple);
11155-
11156- return address;
11157- }
11158-
1115911051/*
1116011052 * Cleanup after we've finished all the ALTER TYPE operations for a
1116111053 * particular relation. We have to drop and recreate all the indexes
11162- * and constraints that depend on the altered columns.
11054+ * and constraints that depend on the altered columns. We do the
11055+ * actual dropping here, but re-creation is managed by adding work
11056+ * queue entries to do those steps later.
1116311057 */
1116411058static void
1116511059ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
@@ -11272,6 +11166,14 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode)
1127211166 */
1127311167}
1127411168
11169+ /*
11170+ * Parse the previously-saved definition string for a constraint or index
11171+ * against the newly-established column data type(s), and queue up the
11172+ * resulting command parsetrees for execution.
11173+ *
11174+ * This might fail if, for example, you have a WHERE clause that uses an
11175+ * operator that's not available for the new column type.
11176+ */
1127511177static void
1127611178ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
1127711179 List **wqueue, LOCKMODE lockmode, bool rewrite)
@@ -11566,6 +11468,116 @@ TryReuseForeignKey(Oid oldId, Constraint *con)
1156611468 ReleaseSysCache(tup);
1156711469}
1156811470
11471+ /*
11472+ * ALTER COLUMN .. OPTIONS ( ... )
11473+ *
11474+ * Returns the address of the modified column
11475+ */
11476+ static ObjectAddress
11477+ ATExecAlterColumnGenericOptions(Relation rel,
11478+ const char *colName,
11479+ List *options,
11480+ LOCKMODE lockmode)
11481+ {
11482+ Relation ftrel;
11483+ Relation attrel;
11484+ ForeignServer *server;
11485+ ForeignDataWrapper *fdw;
11486+ HeapTuple tuple;
11487+ HeapTuple newtuple;
11488+ bool isnull;
11489+ Datum repl_val[Natts_pg_attribute];
11490+ bool repl_null[Natts_pg_attribute];
11491+ bool repl_repl[Natts_pg_attribute];
11492+ Datum datum;
11493+ Form_pg_foreign_table fttableform;
11494+ Form_pg_attribute atttableform;
11495+ AttrNumber attnum;
11496+ ObjectAddress address;
11497+
11498+ if (options == NIL)
11499+ return InvalidObjectAddress;
11500+
11501+ /* First, determine FDW validator associated to the foreign table. */
11502+ ftrel = table_open(ForeignTableRelationId, AccessShareLock);
11503+ tuple = SearchSysCache1(FOREIGNTABLEREL, rel->rd_id);
11504+ if (!HeapTupleIsValid(tuple))
11505+ ereport(ERROR,
11506+ (errcode(ERRCODE_UNDEFINED_OBJECT),
11507+ errmsg("foreign table \"%s\" does not exist",
11508+ RelationGetRelationName(rel))));
11509+ fttableform = (Form_pg_foreign_table) GETSTRUCT(tuple);
11510+ server = GetForeignServer(fttableform->ftserver);
11511+ fdw = GetForeignDataWrapper(server->fdwid);
11512+
11513+ table_close(ftrel, AccessShareLock);
11514+ ReleaseSysCache(tuple);
11515+
11516+ attrel = table_open(AttributeRelationId, RowExclusiveLock);
11517+ tuple = SearchSysCacheAttName(RelationGetRelid(rel), colName);
11518+ if (!HeapTupleIsValid(tuple))
11519+ ereport(ERROR,
11520+ (errcode(ERRCODE_UNDEFINED_COLUMN),
11521+ errmsg("column \"%s\" of relation \"%s\" does not exist",
11522+ colName, RelationGetRelationName(rel))));
11523+
11524+ /* Prevent them from altering a system attribute */
11525+ atttableform = (Form_pg_attribute) GETSTRUCT(tuple);
11526+ attnum = atttableform->attnum;
11527+ if (attnum <= 0)
11528+ ereport(ERROR,
11529+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11530+ errmsg("cannot alter system column \"%s\"", colName)));
11531+
11532+
11533+ /* Initialize buffers for new tuple values */
11534+ memset(repl_val, 0, sizeof(repl_val));
11535+ memset(repl_null, false, sizeof(repl_null));
11536+ memset(repl_repl, false, sizeof(repl_repl));
11537+
11538+ /* Extract the current options */
11539+ datum = SysCacheGetAttr(ATTNAME,
11540+ tuple,
11541+ Anum_pg_attribute_attfdwoptions,
11542+ &isnull);
11543+ if (isnull)
11544+ datum = PointerGetDatum(NULL);
11545+
11546+ /* Transform the options */
11547+ datum = transformGenericOptions(AttributeRelationId,
11548+ datum,
11549+ options,
11550+ fdw->fdwvalidator);
11551+
11552+ if (PointerIsValid(DatumGetPointer(datum)))
11553+ repl_val[Anum_pg_attribute_attfdwoptions - 1] = datum;
11554+ else
11555+ repl_null[Anum_pg_attribute_attfdwoptions - 1] = true;
11556+
11557+ repl_repl[Anum_pg_attribute_attfdwoptions - 1] = true;
11558+
11559+ /* Everything looks good - update the tuple */
11560+
11561+ newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
11562+ repl_val, repl_null, repl_repl);
11563+
11564+ CatalogTupleUpdate(attrel, &newtuple->t_self, newtuple);
11565+
11566+ InvokeObjectPostAlterHook(RelationRelationId,
11567+ RelationGetRelid(rel),
11568+ atttableform->attnum);
11569+ ObjectAddressSubSet(address, RelationRelationId,
11570+ RelationGetRelid(rel), attnum);
11571+
11572+ ReleaseSysCache(tuple);
11573+
11574+ table_close(attrel, RowExclusiveLock);
11575+
11576+ heap_freetuple(newtuple);
11577+
11578+ return address;
11579+ }
11580+
1156911581/*
1157011582 * ALTER TABLE OWNER
1157111583 *
0 commit comments