@@ -382,8 +382,10 @@ static ObjectAddress ATExecDropNotNull(Relation rel, const char *colName, LOCKMO
382382static void ATPrepSetNotNull (Relation rel , bool recurse , bool recursing );
383383static ObjectAddress ATExecSetNotNull (AlteredTableInfo * tab , Relation rel ,
384384 const char * colName , LOCKMODE lockmode );
385+ static void ATPrepSetVisible (Relation rel , bool recurse , bool recursing );
385386static ObjectAddress ATExecSetVisible (AlteredTableInfo * tab , Relation rel ,
386387 const char * colName , LOCKMODE lockmode );
388+ static void ATPrepSetInvisible (Relation rel , bool recurse , bool recursing );
387389static ObjectAddress ATExecSetInvisible (AlteredTableInfo * tab , Relation rel ,
388390 const char * colName , LOCKMODE lockmode );
389391static ObjectAddress ATExecColumnDefault (Relation rel , const char * colName ,
@@ -560,6 +562,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
560562 static char * validnsps [] = HEAP_RELOPT_NAMESPACES ;
561563 Oid ofTypeId ;
562564 ObjectAddress address ;
565+ int invisibleColumnCount ;
563566
564567 /*
565568 * Truncate relname to appropriate length (probably a waste of time, as
@@ -744,6 +747,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
744747 rawDefaults = NIL ;
745748 cookedDefaults = NIL ;
746749 attnum = 0 ;
750+ invisibleColumnCount = 0 ;
747751
748752 foreach (listptr , stmt -> tableElts )
749753 {
@@ -788,9 +792,20 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
788792 attr -> attidentity = colDef -> identity ;
789793
790794 if (colDef -> is_invisible )
795+ {
791796 attr -> attisinvisible = colDef -> is_invisible ;
797+ invisibleColumnCount ++ ;
798+ }
792799 }
793800
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+
794809 /*
795810 * Create the relation. Inherited defaults and constraints are passed in
796811 * for immediate handling --- since they don't need parsing, they can be
@@ -2003,6 +2018,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
20032018 * merge the column options into the column from the type
20042019 */
20052020 coldef -> is_not_null = restdef -> is_not_null ;
2021+ coldef -> is_invisible = restdef -> is_invisible ;
20062022 coldef -> raw_default = restdef -> raw_default ;
20072023 coldef -> cooked_default = restdef -> cooked_default ;
20082024 coldef -> constraints = restdef -> constraints ;
@@ -2246,6 +2262,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
22462262 def -> inhcount = 1 ;
22472263 def -> is_local = false;
22482264 def -> is_not_null = attribute -> attnotnull ;
2265+ def -> is_invisible = attribute -> attisinvisible ;
22492266 def -> is_from_type = false;
22502267 def -> storage = attribute -> attstorage ;
22512268 def -> raw_default = NULL ;
@@ -3843,12 +3860,14 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
38433860 break ;
38443861 case AT_SetVisible : /* ALTER COLUMN SET VISIBLE */
38453862 ATSimplePermissions (rel , ATT_TABLE | ATT_FOREIGN_TABLE );
3863+ ATPrepSetVisible (rel , recurse , recursing );
38463864 ATSimpleRecursion (wqueue , rel , cmd , recurse , lockmode );
38473865 /* No command-specific prep needed */
38483866 pass = AT_PASS_ADD_CONSTR ;
38493867 break ;
38503868 case AT_SetInvisible : /* ALTER COLUMN SET INVISIBLE */
38513869 ATSimplePermissions (rel , ATT_TABLE | ATT_FOREIGN_TABLE );
3870+ ATPrepSetInvisible (rel , recurse , recursing );
38523871 ATSimpleRecursion (wqueue , rel , cmd , recurse , lockmode );
38533872 /* No command-specific prep needed */
38543873 pass = AT_PASS_ADD_CONSTR ;
@@ -6272,6 +6291,25 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
62726291 return address ;
62736292}
62746293
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+
62756313/*
62766314 * Return the address of the modified column. If the column was already Invisible,
62776315 * InvalidObjectAddress is returned.
@@ -6328,6 +6366,25 @@ ATExecSetVisible(AlteredTableInfo *tab, Relation rel,
63286366 return address ;
63296367}
63306368
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+
63316388/*
63326389 * Return the address of the modified column. If the column was already Invisible,
63336390 * InvalidObjectAddress is returned.
@@ -6365,6 +6422,30 @@ ATExecSetInvisible(AlteredTableInfo *tab, Relation rel,
63656422
63666423 if (!((Form_pg_attribute ) GETSTRUCT (tuple ))-> attisinvisible )
63676424 {
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+
63686449 ((Form_pg_attribute ) GETSTRUCT (tuple ))-> attisinvisible = true;
63696450
63706451 CatalogTupleUpdate (attr_rel , & tuple -> t_self , tuple );
0 commit comments