Don't require pg_class.dat to contain correct relnatts values.

Practically everybody who's ever added a column to one of the bootstrap
catalogs has been burnt by the need to update the relnatts field in the
initial pg_class data to match.  Now that we use Perl scripts to
generate postgres.bki, we can have the machines take care of that,
by filling the field during genbki.pl.

While at it, use the BKI_DEFAULTS mechanism to eliminate repetitive
specifications of other column values in pg_class.dat, too.  They
weren't particularly a maintenance problem, but this way is prettier
(certainly the spotty previous usage of BKI_DEFAULTS wasn't pretty).

No catversion bump needed, since this doesn't actually change the
contents of postgres.bki.

Per gripe from Justin Pryzby, though this is quite different from
his originally proposed solution.

Amit Langote, John Naylor, Tom Lane

Discussion: https://postgr.es/m/20200212182337.GZ1412@telsasoft.com
This commit is contained in:
Tom Lane 2020-02-15 14:57:27 -05:00
parent 317906f2a6
commit 86ff085e83
3 changed files with 42 additions and 66 deletions

View File

@ -184,6 +184,15 @@ my $PG_CATALOG_NAMESPACE =
'PG_CATALOG_NAMESPACE');
# Fill in pg_class.relnatts by looking at the referenced catalog's schema.
# This is ugly but there's no better place; Catalog::AddDefaultValues
# can't do it, for lack of easy access to the other catalog.
foreach my $row (@{ $catalog_data{pg_class} })
{
$row->{relnatts} = scalar(@{ $catalogs{ $row->{relname} }->{columns} });
}
# Build lookup tables.
# access method OID lookup

View File

@ -14,51 +14,15 @@
# Note: only bootstrap catalogs, ie those marked BKI_BOOTSTRAP, need to
# have entries here. Be sure that the OIDs listed here match those given in
# their CATALOG and BKI_ROWTYPE_OID macros, and that the relnatts values are
# correct.
# Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId;
# similarly, "1" in relminmxid stands for FirstMultiXactId
# their CATALOG and BKI_ROWTYPE_OID macros.
{ oid => '1247',
relname => 'pg_type', reltype => 'pg_type', relam => 'heap',
relfilenode => '0', relpages => '0', reltuples => '0', relallvisible => '0',
reltoastrelid => '0', relhasindex => 'f', relisshared => 'f',
relpersistence => 'p', relkind => 'r', relnatts => '31', relchecks => '0',
relhasrules => 'f', relhastriggers => 'f', relhassubclass => 'f',
relrowsecurity => 'f', relforcerowsecurity => 'f', relispopulated => 't',
relreplident => 'n', relispartition => 'f', relfrozenxid => '3',
relminmxid => '1', relacl => '_null_', reloptions => '_null_',
relpartbound => '_null_' },
relname => 'pg_type', reltype => 'pg_type' },
{ oid => '1249',
relname => 'pg_attribute', reltype => 'pg_attribute', relam => 'heap',
relfilenode => '0', relpages => '0', reltuples => '0', relallvisible => '0',
reltoastrelid => '0', relhasindex => 'f', relisshared => 'f',
relpersistence => 'p', relkind => 'r', relnatts => '25', relchecks => '0',
relhasrules => 'f', relhastriggers => 'f', relhassubclass => 'f',
relrowsecurity => 'f', relforcerowsecurity => 'f', relispopulated => 't',
relreplident => 'n', relispartition => 'f', relfrozenxid => '3',
relminmxid => '1', relacl => '_null_', reloptions => '_null_',
relpartbound => '_null_' },
relname => 'pg_attribute', reltype => 'pg_attribute' },
{ oid => '1255',
relname => 'pg_proc', reltype => 'pg_proc', relam => 'heap',
relfilenode => '0', relpages => '0', reltuples => '0', relallvisible => '0',
reltoastrelid => '0', relhasindex => 'f', relisshared => 'f',
relpersistence => 'p', relkind => 'r', relnatts => '29', relchecks => '0',
relhasrules => 'f', relhastriggers => 'f', relhassubclass => 'f',
relrowsecurity => 'f', relforcerowsecurity => 'f', relispopulated => 't',
relreplident => 'n', relispartition => 'f', relfrozenxid => '3',
relminmxid => '1', relacl => '_null_', reloptions => '_null_',
relpartbound => '_null_' },
relname => 'pg_proc', reltype => 'pg_proc' },
{ oid => '1259',
relname => 'pg_class', reltype => 'pg_class', relam => 'heap',
relfilenode => '0', relpages => '0', reltuples => '0', relallvisible => '0',
reltoastrelid => '0', relhasindex => 'f', relisshared => 'f',
relpersistence => 'p', relkind => 'r', relnatts => '33', relchecks => '0',
relhasrules => 'f', relhastriggers => 'f', relhassubclass => 'f',
relrowsecurity => 'f', relforcerowsecurity => 'f', relispopulated => 't',
relreplident => 'n', relispartition => 'f', relfrozenxid => '3',
relminmxid => '1', relacl => '_null_', reloptions => '_null_',
relpartbound => '_null_' },
relname => 'pg_class', reltype => 'pg_class' },
]

View File

@ -24,6 +24,9 @@
/* ----------------
* pg_class definition. cpp turns this into
* typedef struct FormData_pg_class
*
* Note that the BKI_DEFAULT values below are only used for rows describing
* BKI_BOOTSTRAP catalogs, since only those rows appear in pg_class.dat.
* ----------------
*/
CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,RelationRelation_Rowtype_Id) BKI_SCHEMA_MACRO
@ -47,41 +50,41 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat
Oid relowner BKI_DEFAULT(PGUID);
/* access method; 0 if not a table / index */
Oid relam BKI_LOOKUP(pg_am);
Oid relam BKI_DEFAULT(heap) BKI_LOOKUP(pg_am);
/* identifier of physical storage file */
/* relfilenode == 0 means it is a "mapped" relation, see relmapper.c */
Oid relfilenode;
Oid relfilenode BKI_DEFAULT(0);
/* identifier of table space for relation (0 means default for database) */
Oid reltablespace BKI_DEFAULT(0) BKI_LOOKUP(pg_tablespace);
/* # of blocks (not always up-to-date) */
int32 relpages;
int32 relpages BKI_DEFAULT(0);
/* # of tuples (not always up-to-date) */
float4 reltuples;
float4 reltuples BKI_DEFAULT(0);
/* # of all-visible blocks (not always up-to-date) */
int32 relallvisible;
int32 relallvisible BKI_DEFAULT(0);
/* OID of toast table; 0 if none */
Oid reltoastrelid;
Oid reltoastrelid BKI_DEFAULT(0);
/* T if has (or has had) any indexes */
bool relhasindex;
bool relhasindex BKI_DEFAULT(f);
/* T if shared across databases */
bool relisshared;
bool relisshared BKI_DEFAULT(f);
/* see RELPERSISTENCE_xxx constants below */
char relpersistence;
char relpersistence BKI_DEFAULT(p);
/* see RELKIND_xxx constants below */
char relkind;
char relkind BKI_DEFAULT(r);
/* number of user attributes */
int16 relnatts;
int16 relnatts BKI_DEFAULT(0); /* genbki.pl will fill this in */
/*
* Class pg_attribute must contain exactly "relnatts" user attributes
@ -90,51 +93,51 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat
*/
/* # of CHECK constraints for class */
int16 relchecks;
int16 relchecks BKI_DEFAULT(0);
/* has (or has had) any rules */
bool relhasrules;
bool relhasrules BKI_DEFAULT(f);
/* has (or has had) any TRIGGERs */
bool relhastriggers;
bool relhastriggers BKI_DEFAULT(f);
/* has (or has had) child tables or indexes */
bool relhassubclass;
bool relhassubclass BKI_DEFAULT(f);
/* row security is enabled or not */
bool relrowsecurity;
bool relrowsecurity BKI_DEFAULT(f);
/* row security forced for owners or not */
bool relforcerowsecurity;
bool relforcerowsecurity BKI_DEFAULT(f);
/* matview currently holds query results */
bool relispopulated;
bool relispopulated BKI_DEFAULT(t);
/* see REPLICA_IDENTITY_xxx constants */
char relreplident;
char relreplident BKI_DEFAULT(n);
/* is relation a partition? */
bool relispartition;
bool relispartition BKI_DEFAULT(f);
/* heap for rewrite during DDL, link to original rel */
Oid relrewrite BKI_DEFAULT(0);
/* all Xids < this are frozen in this rel */
TransactionId relfrozenxid;
TransactionId relfrozenxid BKI_DEFAULT(3); /* FirstNormalTransactionId */
/* all multixacts in this rel are >= this; it is really a MultiXactId */
TransactionId relminmxid;
TransactionId relminmxid BKI_DEFAULT(1); /* FirstMultiXactId */
#ifdef CATALOG_VARLEN /* variable-length fields start here */
/* NOTE: These fields are not present in a relcache entry's rd_rel field. */
/* access permissions */
aclitem relacl[1];
aclitem relacl[1] BKI_DEFAULT(_null_);
/* access-method-specific options */
text reloptions[1];
text reloptions[1] BKI_DEFAULT(_null_);
/* partition bound node tree */
pg_node_tree relpartbound;
pg_node_tree relpartbound BKI_DEFAULT(_null_);
#endif
} FormData_pg_class;