Hi,

On 2018-11-20 11:25:22 -0500, Stephen Frost wrote:
> Greetings,
> 
> * Robert Haas (robertmh...@gmail.com) wrote:
> > On Sun, Oct 14, 2018 at 6:35 PM Tom Lane <t...@sss.pgh.pa.us> wrote:
> > > Andres Freund <and...@anarazel.de> writes:
> > > > Does anybody have engineering / architecture level comments about this
> > > > proposal?
> > >
> > > FWIW, I'm -1 on making OIDs be not-magic for SELECT purposes.  Yeah, it's
> > > a wart we wouldn't have if we designed the system today, but the wart is
> > > thirty years old.  I think changing that will break so many catalog
> > > queries that we'll have the villagers on the doorstep.  Most of the other
> > > things you're suggesting here could be done easily without making that
> > > change.
> > >
> > > Possibly we could make them not-magic from the storage standpoint (ie
> > > they're regular columns) but have a pg_attribute flag that says not
> > > to include them in "SELECT *" expansion.
> > 
> > I think such a flag would be a good idea; it seems to have other uses.
> > As Andres also noted, Kevin was quite interested in having a
> > hidden-by-default COUNT column to assist with materialized view
> > maintenance, and presumably this could also be used for that purpose.
> 
> Yeah, I like the idea of having this column too, it'd also be useful for
> people who are trying to use column-level privileges.

FWIW, leaving grammar bikeshedding aside, I don't think this is
particularly hard.  There certainly are a few corner cases I've not
touched here, but the attached implements the basic features for hidden
columns.


postgres[14805][1]=# CREATE TABLE blarg(id serial, data text, annotation text);
postgres[14805][1]=# INSERT INTO blarg (data, annotation) VALUES ('42', 'this 
is THE question');

postgres[14805][1]=# SELECT * FROM blarg;
┌────┬──────┬──────────────────────┐
│ id │ data │      annotation      │
├────┼──────┼──────────────────────┤
│  1 │ 42   │ this is THE question │
└────┴──────┴──────────────────────┘
(1 row)

postgres[14805][1]=# SELECT s.* FROM (SELECT * FROM blarg) s;
┌────┬──────┬──────────────────────┐
│ id │ data │      annotation      │
├────┼──────┼──────────────────────┤
│  1 │ 42   │ this is THE question │
└────┴──────┴──────────────────────┘
(1 row)

postgres[14805][1]=# SELECT s.* FROM (SELECT blarg FROM blarg) s;
┌───────────────────────────────┐
│             blarg             │
├───────────────────────────────┤
│ (1,42,"this is THE question") │
└───────────────────────────────┘
(1 row)


postgres[14805][1]=# SELECT s.annotation FROM (SELECT * FROM blarg) s;
┌──────────────────────┐
│      annotation      │
├──────────────────────┤
│ this is THE question │
└──────────────────────┘
(1 row)

postgres[14805][1]=# SELECT (s.blarg).annotation FROM (SELECT blarg FROM blarg) 
s;
┌──────────────────────┐
│      annotation      │
├──────────────────────┤
│ this is THE question │
└──────────────────────┘
(1 row)


-- update column to be hidden
postgres[14805][1]=# UPDATE pg_attribute SET attishidden = true WHERE attrelid 
= 'blarg'::regclass AND attname = 'annotation';

postgres[14805][1]=# SELECT * FROM blarg;
┌────┬──────┐
│ id │ data │
├────┼──────┤
│  1 │ 42   │
└────┴──────┘
(1 row)

postgres[14805][1]=# SELECT s.* FROM (SELECT * FROM blarg) s;
┌────┬──────┐
│ id │ data │
├────┼──────┤
│  1 │ 42   │
└────┴──────┘
(1 row)

postgres[14805][1]=# SELECT s.blarg FROM (SELECT blarg FROM blarg) s;
┌───────────────────────────────┐
│             blarg             │
├───────────────────────────────┤
│ (1,42,"this is THE question") │
└───────────────────────────────┘
(1 row)

postgres[14805][1]=# SELECT s.annotation FROM (SELECT * FROM blarg) s;
ERROR:  42703: column s.annotation does not exist
LINE 1: SELECT s.annotation FROM (SELECT * FROM blarg) s;
               ^
LOCATION:  errorMissingColumn, parse_relation.c:3319

postgres[14805][1]=# SELECT (s.blarg).annotation FROM (SELECT blarg FROM blarg) 
s;
┌──────────────────────┐
│      annotation      │
├──────────────────────┤
│ this is THE question │
└──────────────────────┘
(1 row)

postgres[14805][1]=# SELECT (s.blarg).* FROM (SELECT blarg FROM blarg) s;
┌────┬──────┐
│ id │ data │
├────┼──────┤
│  1 │ 42   │
└────┴──────┘
(1 row)


It's debatable if a wholerow-var select (without *, i.e the s.blarg case
above)) ought to include the hidden column, but to me that intuitively
makes sense. Otherwise you couldn't select it after a cast and such.

Greetings,

Andres Freund
diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index 5354a04639b..78934c11de1 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -461,6 +461,8 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
 			return false;
 		if (attr1->attislocal != attr2->attislocal)
 			return false;
+		if (attr1->attishidden != attr2->attishidden)
+			return false;
 		if (attr1->attinhcount != attr2->attinhcount)
 			return false;
 		if (attr1->attcollation != attr2->attcollation)
@@ -641,6 +643,7 @@ TupleDescInitEntry(TupleDesc desc,
 	att->attidentity = '\0';
 	att->attisdropped = false;
 	att->attislocal = true;
+	att->attishidden = false;
 	att->attinhcount = 0;
 	/* attacl, attoptions and attfdwoptions are not present in tupledescs */
 
@@ -700,6 +703,7 @@ TupleDescInitBuiltinEntry(TupleDesc desc,
 	att->attidentity = '\0';
 	att->attisdropped = false;
 	att->attislocal = true;
+	att->attishidden = false;
 	att->attinhcount = 0;
 	/* attacl, attoptions and attfdwoptions are not present in tupledescs */
 
@@ -791,6 +795,7 @@ BuildDescForRelation(List *schema)
 	int32		atttypmod;
 	Oid			attcollation;
 	int			attdim;
+	bool		attishidden;
 
 	/*
 	 * allocate a new tuple descriptor
@@ -843,6 +848,7 @@ BuildDescForRelation(List *schema)
 		att->attnotnull = entry->is_not_null;
 		has_not_null |= entry->is_not_null;
 		att->attislocal = entry->is_local;
+		att->attishidden = false;
 		att->attinhcount = entry->inhcount;
 	}
 
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 8e2cf7df562..acad35de08c 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -748,6 +748,7 @@ DefineAttr(char *name, char *type, int attnum, int nullness)
 	attrtypes[attnum]->attcacheoff = -1;
 	attrtypes[attnum]->atttypmod = -1;
 	attrtypes[attnum]->attislocal = true;
+	attrtypes[attnum]->attishidden = false;
 
 	if (nullness == BOOTCOL_NULL_FORCE_NOT_NULL)
 	{
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 378cbcbf79e..3c6875e0e0d 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -2596,6 +2596,13 @@ expandTupleDesc(TupleDesc tupdesc, Alias *eref, int count, int offset,
 			continue;
 		}
 
+		/*
+		 * Skip over hidden fields, unless reproducing a closely matching
+		 * entry (FIXME: check callers whether that's sensible).
+		 */
+		if (attr->attishidden && !include_dropped)
+			continue;
+
 		if (colnames)
 		{
 			char	   *label;
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index b8702d914dc..0e27cd6b100 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1434,7 +1434,7 @@ ExpandRowReference(ParseState *pstate, Node *expr,
 		Form_pg_attribute att = TupleDescAttr(tupleDesc, i);
 		FieldSelect *fselect;
 
-		if (att->attisdropped)
+		if (att->attisdropped || att->attishidden)
 			continue;
 
 		fselect = makeNode(FieldSelect);
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h
index 1bac59bf26e..dbad2ebf5be 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -154,6 +154,9 @@ CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,
 	 */
 	bool		attislocal BKI_DEFAULT(t);
 
+	/* column included in SELECT * expansion */
+	bool		attishidden BKI_DEFAULT(f);
+
 	/* Number of times inherited from direct parent relation(s) */
 	int32		attinhcount BKI_DEFAULT(0);
 
diff --git a/src/include/catalog/pg_class.dat b/src/include/catalog/pg_class.dat
index 5a884a852b5..e6d5e2cdda9 100644
--- a/src/include/catalog/pg_class.dat
+++ b/src/include/catalog/pg_class.dat
@@ -36,7 +36,7 @@
   reloftype => '0', relowner => 'PGUID', relam => '0', relfilenode => '0',
   reltablespace => '0', relpages => '0', reltuples => '0', relallvisible => '0',
   reltoastrelid => '0', relhasindex => 'f', relisshared => 'f',
-  relpersistence => 'p', relkind => 'r', relnatts => '24', relchecks => '0',
+  relpersistence => 'p', relkind => 'r', relnatts => '25', relchecks => '0',
   relhasrules => 'f', relhastriggers => 'f', relhassubclass => 'f',
   relrowsecurity => 'f', relforcerowsecurity => 'f', relispopulated => 't',
   relreplident => 'n', relispartition => 'f', relrewrite => '0',

Reply via email to