@@ -382,8 +382,10 @@ static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMO
382
382
static void ATPrepSetNotNull (Relation rel , bool recurse , bool recursing );
383
383
static ObjectAddress ATExecSetNotNull (AlteredTableInfo * tab , Relation rel ,
384
384
const char * colName , LOCKMODE lockmode );
385
+ static void ATPrepSetVisible (Relation rel , bool recurse , bool recursing );
385
386
static ObjectAddress ATExecSetVisible (AlteredTableInfo * tab , Relation rel ,
386
387
const char * colName , LOCKMODE lockmode );
388
+ static void ATPrepSetInvisible (Relation rel , bool recurse , bool recursing );
387
389
static ObjectAddress ATExecSetInvisible (AlteredTableInfo * tab , Relation rel ,
388
390
const char * colName , LOCKMODE lockmode );
389
391
static ObjectAddress ATExecColumnDefault (Relation rel , const char * colName ,
@@ -560,6 +562,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
560
562
static char * validnsps [] = HEAP_RELOPT_NAMESPACES ;
561
563
Oid ofTypeId ;
562
564
ObjectAddress address ;
565
+ int invisibleColumnCount ;
563
566
564
567
/*
565
568
* Truncate relname to appropriate length (probably a waste of time, as
@@ -744,6 +747,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
744
747
rawDefaults = NIL ;
745
748
cookedDefaults = NIL ;
746
749
attnum = 0 ;
750
+ invisibleColumnCount = 0 ;
747
751
748
752
foreach (listptr , stmt -> tableElts )
749
753
{
@@ -788,9 +792,20 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
788
792
attr -> attidentity = colDef -> identity ;
789
793
790
794
if (colDef -> is_invisible )
795
+ {
791
796
attr -> attisinvisible = colDef -> is_invisible ;
797
+ invisibleColumnCount ++ ;
798
+ }
792
799
}
793
800
801
+ /*
802
+ * table must have at least one column that is not invisible
803
+ */
804
+ if (invisibleColumnCount == attnum )
805
+ ereport (ERROR ,
806
+ (errcode (ERRCODE_SYNTAX_ERROR ),
807
+ errmsg ("table must have at least one column that is not invisible" )));
808
+
794
809
/*
795
810
* Create the relation. Inherited defaults and constraints are passed in
796
811
* for immediate handling --- since they don't need parsing, they can be
@@ -2003,6 +2018,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
2003
2018
* merge the column options into the column from the type
2004
2019
*/
2005
2020
coldef -> is_not_null = restdef -> is_not_null ;
2021
+ coldef -> is_invisible = restdef -> is_invisible ;
2006
2022
coldef -> raw_default = restdef -> raw_default ;
2007
2023
coldef -> cooked_default = restdef -> cooked_default ;
2008
2024
coldef -> constraints = restdef -> constraints ;
@@ -2246,6 +2262,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
2246
2262
def -> inhcount = 1 ;
2247
2263
def -> is_local = false;
2248
2264
def -> is_not_null = attribute -> attnotnull ;
2265
+ def -> is_invisible = attribute -> attisinvisible ;
2249
2266
def -> is_from_type = false;
2250
2267
def -> storage = attribute -> attstorage ;
2251
2268
def -> raw_default = NULL ;
@@ -3843,12 +3860,14 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
3843
3860
break ;
3844
3861
case AT_SetVisible : /* ALTER COLUMN SET VISIBLE */
3845
3862
ATSimplePermissions (rel , ATT_TABLE | ATT_FOREIGN_TABLE );
3863
+ ATPrepSetVisible (rel , recurse , recursing );
3846
3864
ATSimpleRecursion (wqueue , rel , cmd , recurse , lockmode );
3847
3865
/* No command-specific prep needed */
3848
3866
pass = AT_PASS_ADD_CONSTR ;
3849
3867
break ;
3850
3868
case AT_SetInvisible : /* ALTER COLUMN SET INVISIBLE */
3851
3869
ATSimplePermissions (rel , ATT_TABLE | ATT_FOREIGN_TABLE );
3870
+ ATPrepSetInvisible (rel , recurse , recursing );
3852
3871
ATSimpleRecursion (wqueue , rel , cmd , recurse , lockmode );
3853
3872
/* No command-specific prep needed */
3854
3873
pass = AT_PASS_ADD_CONSTR ;
@@ -6272,6 +6291,25 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
6272
6291
return address ;
6273
6292
}
6274
6293
6294
+ static void
6295
+ ATPrepSetVisible (Relation rel , bool recurse , bool recursing )
6296
+ {
6297
+ /*
6298
+ * If the parent is a partitioned table, Set Visible
6299
+ * constraints must be added to the child tables.
6300
+ */
6301
+ if (rel -> rd_rel -> relkind == RELKIND_PARTITIONED_TABLE )
6302
+ {
6303
+ PartitionDesc partdesc = RelationGetPartitionDesc (rel );
6304
+
6305
+ if (partdesc && partdesc -> nparts > 0 && !recurse && !recursing )
6306
+ ereport (ERROR ,
6307
+ (errcode (ERRCODE_INVALID_TABLE_DEFINITION ),
6308
+ errmsg ("cannot add constraint to only the partitioned table when partitions exist" ),
6309
+ errhint ("Do not specify the ONLY keyword." )));
6310
+ }
6311
+ }
6312
+
6275
6313
/*
6276
6314
* Return the address of the modified column. If the column was already Invisible,
6277
6315
* InvalidObjectAddress is returned.
@@ -6328,6 +6366,25 @@ ATExecSetVisible(AlteredTableInfo *tab, Relation rel,
6328
6366
return address ;
6329
6367
}
6330
6368
6369
+ static void
6370
+ ATPrepSetInvisible (Relation rel , bool recurse , bool recursing )
6371
+ {
6372
+ /*
6373
+ * If the parent is a partitioned table, Set Invisible
6374
+ * constraints must be added to the child tables.
6375
+ */
6376
+ if (rel -> rd_rel -> relkind == RELKIND_PARTITIONED_TABLE )
6377
+ {
6378
+ PartitionDesc partdesc = RelationGetPartitionDesc (rel );
6379
+
6380
+ if (partdesc && partdesc -> nparts > 0 && !recurse && !recursing )
6381
+ ereport (ERROR ,
6382
+ (errcode (ERRCODE_INVALID_TABLE_DEFINITION ),
6383
+ errmsg ("cannot add constraint to only the partitioned table when partitions exist" ),
6384
+ errhint ("Do not specify the ONLY keyword." )));
6385
+ }
6386
+ }
6387
+
6331
6388
/*
6332
6389
* Return the address of the modified column. If the column was already Invisible,
6333
6390
* InvalidObjectAddress is returned.
@@ -6365,6 +6422,30 @@ ATExecSetInvisible(AlteredTableInfo *tab, Relation rel,
6365
6422
6366
6423
if (!((Form_pg_attribute ) GETSTRUCT (tuple ))-> attisinvisible )
6367
6424
{
6425
+ TupleDesc tupleDesc = RelationGetDescr (rel );
6426
+ int numattrs = tupleDesc -> natts ;
6427
+ int i ;
6428
+ bool visible_only = true;
6429
+ Form_pg_attribute attr ;
6430
+
6431
+ for (i = 0 ; i < numattrs ; ++ i ) {
6432
+ if (i == attnum - 1 ) {
6433
+ continue ;
6434
+ }
6435
+
6436
+ attr = TupleDescAttr (tupleDesc , i );
6437
+
6438
+ if (!attr -> attisinvisible ) {
6439
+ visible_only = false;
6440
+ break ;
6441
+ }
6442
+ }
6443
+
6444
+ if (visible_only )
6445
+ ereport (ERROR ,
6446
+ (errcode (ERRCODE_SYNTAX_ERROR ),
6447
+ errmsg ("table must have at least one column that is not invisible" )));
6448
+
6368
6449
((Form_pg_attribute ) GETSTRUCT (tuple ))-> attisinvisible = true;
6369
6450
6370
6451
CatalogTupleUpdate (attr_rel , & tuple -> t_self , tuple );
0 commit comments