@@ -346,6 +346,8 @@ static void ATPrepAlterColumnType(List **wqueue,
346
346
static bool ATColumnChangeRequiresRewrite (Node * expr , AttrNumber varattno );
347
347
static void ATExecAlterColumnType (AlteredTableInfo * tab , Relation rel ,
348
348
AlterTableCmd * cmd , LOCKMODE lockmode );
349
+ static void ATExecAlterColumnGenericOptions (Relation rel , const char * colName ,
350
+ List * options , LOCKMODE lockmode );
349
351
static void ATPostAlterTypeCleanup (List * * wqueue , AlteredTableInfo * tab , LOCKMODE lockmode );
350
352
static void ATPostAlterTypeParse (Oid oldId , char * cmd ,
351
353
List * * wqueue , LOCKMODE lockmode , bool rewrite );
@@ -2648,6 +2650,7 @@ AlterTableGetLockLevel(List *cmds)
2648
2650
case AT_DropNotNull : /* may change some SQL plans */
2649
2651
case AT_SetNotNull :
2650
2652
case AT_GenericOptions :
2653
+ case AT_AlterColumnGenericOptions :
2651
2654
cmd_lockmode = AccessExclusiveLock ;
2652
2655
break ;
2653
2656
@@ -2925,6 +2928,12 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
2925
2928
ATPrepAlterColumnType (wqueue , tab , rel , recurse , recursing , cmd , lockmode );
2926
2929
pass = AT_PASS_ALTER_TYPE ;
2927
2930
break ;
2931
+ case AT_AlterColumnGenericOptions :
2932
+ ATSimplePermissions (rel , ATT_FOREIGN_TABLE );
2933
+ /* This command never recurses */
2934
+ /* No command-specific prep needed */
2935
+ pass = AT_PASS_MISC ;
2936
+ break ;
2928
2937
case AT_ChangeOwner : /* ALTER OWNER */
2929
2938
/* This command never recurses */
2930
2939
/* No command-specific prep needed */
@@ -3169,6 +3178,9 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
3169
3178
case AT_AlterColumnType : /* ALTER COLUMN TYPE */
3170
3179
ATExecAlterColumnType (tab , rel , cmd , lockmode );
3171
3180
break ;
3181
+ case AT_AlterColumnGenericOptions : /* ALTER COLUMN OPTIONS */
3182
+ ATExecAlterColumnGenericOptions (rel , cmd -> name , (List * ) cmd -> def , lockmode );
3183
+ break ;
3172
3184
case AT_ChangeOwner : /* ALTER OWNER */
3173
3185
ATExecChangeOwner (RelationGetRelid (rel ),
3174
3186
get_role_oid (cmd -> name , false),
@@ -7397,6 +7409,100 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
7397
7409
heap_freetuple (heapTup );
7398
7410
}
7399
7411
7412
+ static void
7413
+ ATExecAlterColumnGenericOptions (Relation rel ,
7414
+ const char * colName ,
7415
+ List * options ,
7416
+ LOCKMODE lockmode )
7417
+ {
7418
+ Relation ftrel ;
7419
+ Relation attrel ;
7420
+ ForeignServer * server ;
7421
+ ForeignDataWrapper * fdw ;
7422
+ HeapTuple tuple ;
7423
+ HeapTuple newtuple ;
7424
+ bool isnull ;
7425
+ Datum repl_val [Natts_pg_attribute ];
7426
+ bool repl_null [Natts_pg_attribute ];
7427
+ bool repl_repl [Natts_pg_attribute ];
7428
+ Datum datum ;
7429
+ Form_pg_foreign_table fttableform ;
7430
+ Form_pg_attribute atttableform ;
7431
+
7432
+ if (options == NIL )
7433
+ return ;
7434
+
7435
+ /* First, determine FDW validator associated to the foreign table. */
7436
+ ftrel = heap_open (ForeignTableRelationId , AccessShareLock );
7437
+ tuple = SearchSysCache1 (FOREIGNTABLEREL , rel -> rd_id );
7438
+ if (!HeapTupleIsValid (tuple ))
7439
+ ereport (ERROR ,
7440
+ (errcode (ERRCODE_UNDEFINED_OBJECT ),
7441
+ errmsg ("foreign table \"%s\" does not exist" ,
7442
+ RelationGetRelationName (rel ))));
7443
+ fttableform = (Form_pg_foreign_table ) GETSTRUCT (tuple );
7444
+ server = GetForeignServer (fttableform -> ftserver );
7445
+ fdw = GetForeignDataWrapper (server -> fdwid );
7446
+
7447
+ heap_close (ftrel , AccessShareLock );
7448
+ ReleaseSysCache (tuple );
7449
+
7450
+ attrel = heap_open (AttributeRelationId , RowExclusiveLock );
7451
+ tuple = SearchSysCacheAttName (RelationGetRelid (rel ), colName );
7452
+ if (!HeapTupleIsValid (tuple ))
7453
+ ereport (ERROR ,
7454
+ (errcode (ERRCODE_UNDEFINED_COLUMN ),
7455
+ errmsg ("column \"%s\" of relation \"%s\" does not exist" ,
7456
+ colName , RelationGetRelationName (rel ))));
7457
+
7458
+ /* Prevent them from altering a system attribute */
7459
+ atttableform = (Form_pg_attribute ) GETSTRUCT (tuple );
7460
+ if (atttableform -> attnum <= 0 )
7461
+ ereport (ERROR ,
7462
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
7463
+ errmsg ("cannot alter system column \"%s\"" , colName )));
7464
+
7465
+
7466
+ /* Initialize buffers for new tuple values */
7467
+ memset (repl_val , 0 , sizeof (repl_val ));
7468
+ memset (repl_null , false, sizeof (repl_null ));
7469
+ memset (repl_repl , false, sizeof (repl_repl ));
7470
+
7471
+ /* Extract the current options */
7472
+ datum = SysCacheGetAttr (ATTNAME ,
7473
+ tuple ,
7474
+ Anum_pg_attribute_attfdwoptions ,
7475
+ & isnull );
7476
+ if (isnull )
7477
+ datum = PointerGetDatum (NULL );
7478
+
7479
+ /* Transform the options */
7480
+ datum = transformGenericOptions (AttributeRelationId ,
7481
+ datum ,
7482
+ options ,
7483
+ fdw -> fdwvalidator );
7484
+
7485
+ if (PointerIsValid (DatumGetPointer (datum )))
7486
+ repl_val [Anum_pg_attribute_attfdwoptions - 1 ] = datum ;
7487
+ else
7488
+ repl_null [Anum_pg_attribute_attfdwoptions - 1 ] = true;
7489
+
7490
+ repl_repl [Anum_pg_attribute_attfdwoptions - 1 ] = true;
7491
+
7492
+ /* Everything looks good - update the tuple */
7493
+
7494
+ newtuple = heap_modify_tuple (tuple , RelationGetDescr (attrel ),
7495
+ repl_val , repl_null , repl_repl );
7496
+ ReleaseSysCache (tuple );
7497
+
7498
+ simple_heap_update (attrel , & newtuple -> t_self , newtuple );
7499
+ CatalogUpdateIndexes (attrel , newtuple );
7500
+
7501
+ heap_close (attrel , RowExclusiveLock );
7502
+
7503
+ heap_freetuple (newtuple );
7504
+ }
7505
+
7400
7506
/*
7401
7507
* Cleanup after we've finished all the ALTER TYPE operations for a
7402
7508
* particular relation. We have to drop and recreate all the indexes
0 commit comments