From f3faf35f370f558670c8213a08f2683f3811ffc7 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 7 Jul 2020 15:43:22 -0400 Subject: [PATCH] Don't create pg_type entries for sequences or toast tables. Commit f7f70d5e2 left one inconsistency behind: we're still creating pg_type entries for the composite types of sequences and toast tables, but not arrays over those composites. But there seems precious little reason to have named composite types for toast tables, and not much more to have them for sequences (especially given the thought that sequences may someday not be standalone relations at all). So, let's close that inconsistency by removing these composite types, rather than adding arrays for them. This buys back a little bit of the initial pg_type bloat added by the previous patch, and could be a significant savings in a large database with many toast tables. Aside from a small logic rearrangement in heap_create_with_catalog, this patch mostly needs to clean up some places that were assuming that pg_class.reltype always has a valid value. Those are really pre-existing bugs, given that it's documented otherwise; notably, the plpgsql changes fix code that gives "cache lookup failed for type 0" on indexes today. But none of these seem interesting enough to back-patch. Also, remove the pg_dump/pg_upgrade infrastructure for propagating a toast table's pg_type OID into the new database, since we no longer need that. Discussion: https://postgr.es/m/761F1389-C6A8-4C15-80CE-950C961F5341@gmail.com --- doc/src/sgml/catalogs.sgml | 3 +- src/backend/catalog/heap.c | 75 +++++++++++++--------- src/backend/catalog/toasting.c | 20 +----- src/backend/commands/tablecmds.c | 22 +++---- src/backend/nodes/makefuncs.c | 6 +- src/backend/utils/adt/pg_upgrade_support.c | 11 ---- src/backend/utils/cache/relcache.c | 13 ++-- src/bin/pg_dump/pg_dump.c | 46 ++++--------- src/include/catalog/binary_upgrade.h | 1 - src/include/catalog/catversion.h | 2 +- src/include/catalog/pg_proc.dat | 4 -- src/pl/plpgsql/src/pl_comp.c | 22 ++++++- 12 files changed, 102 insertions(+), 123 deletions(-) diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 361793b337..e9cdff4864 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1895,7 +1895,8 @@ SCRAM-SHA-256$<iteration count>:&l The OID of the data type that corresponds to this table's row type, - if any (zero for indexes, which have no pg_type entry) + if any (zero for indexes, sequences, and toast tables, which have + no pg_type entry) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index fd04e82b20..3985326df6 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -1000,7 +1000,9 @@ AddNewRelationTuple(Relation pg_class_desc, /* relispartition is always set by updating this tuple later */ new_rel_reltup->relispartition = false; - new_rel_desc->rd_att->tdtypeid = new_type_oid; + /* fill rd_att's type ID with something sane even if reltype is zero */ + new_rel_desc->rd_att->tdtypeid = new_type_oid ? new_type_oid : RECORDOID; + new_rel_desc->rd_att->tdtypmod = -1; /* Now build and insert the tuple */ InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, @@ -1085,6 +1087,7 @@ AddNewRelationType(const char *typeName, * * Output parameters: * typaddress: if not null, gets the object address of the new pg_type entry + * (this must be null if the relkind is one that doesn't get a pg_type entry) * * Returns the OID of the new relation * -------------------------------- @@ -1118,8 +1121,6 @@ heap_create_with_catalog(const char *relname, Oid existing_relid; Oid old_type_oid; Oid new_type_oid; - ObjectAddress new_type_addr; - Oid new_array_oid = InvalidOid; TransactionId relfrozenxid; MultiXactId relminmxid; @@ -1262,44 +1263,46 @@ heap_create_with_catalog(const char *relname, new_rel_desc->rd_rel->relrewrite = relrewrite; /* - * Decide whether to create an array type over the relation's rowtype. - * Array types are made except where the use of a relation as such is an + * Decide whether to create a pg_type entry for the relation's rowtype. + * These types are made except where the use of a relation as such is an * implementation detail: toast tables, sequences and indexes. */ if (!(relkind == RELKIND_SEQUENCE || relkind == RELKIND_TOASTVALUE || relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX)) - new_array_oid = AssignTypeArrayOid(); - - /* - * Since defining a relation also defines a complex type, we add a new - * system type corresponding to the new relation. The OID of the type can - * be preselected by the caller, but if reltypeid is InvalidOid, we'll - * generate a new OID for it. - * - * NOTE: we could get a unique-index failure here, in case someone else is - * creating the same type name in parallel but hadn't committed yet when - * we checked for a duplicate name above. - */ - new_type_addr = AddNewRelationType(relname, - relnamespace, - relid, - relkind, - ownerid, - reltypeid, - new_array_oid); - new_type_oid = new_type_addr.objectId; - if (typaddress) - *typaddress = new_type_addr; - - /* - * Now make the array type if wanted. - */ - if (OidIsValid(new_array_oid)) { + Oid new_array_oid; + ObjectAddress new_type_addr; char *relarrayname; + /* + * We'll make an array over the composite type, too. For largely + * historical reasons, the array type's OID is assigned first. + */ + new_array_oid = AssignTypeArrayOid(); + + /* + * Make the pg_type entry for the composite type. The OID of the + * composite type can be preselected by the caller, but if reltypeid + * is InvalidOid, we'll generate a new OID for it. + * + * NOTE: we could get a unique-index failure here, in case someone + * else is creating the same type name in parallel but hadn't + * committed yet when we checked for a duplicate name above. + */ + new_type_addr = AddNewRelationType(relname, + relnamespace, + relid, + relkind, + ownerid, + reltypeid, + new_array_oid); + new_type_oid = new_type_addr.objectId; + if (typaddress) + *typaddress = new_type_addr; + + /* Now create the array type. */ relarrayname = makeArrayTypeName(relname, relnamespace); TypeCreate(new_array_oid, /* force the type's OID to this */ @@ -1336,6 +1339,14 @@ heap_create_with_catalog(const char *relname, pfree(relarrayname); } + else + { + /* Caller should not be expecting a type to be created. */ + Assert(reltypeid == InvalidOid); + Assert(typaddress == NULL); + + new_type_oid = InvalidOid; + } /* * now create an entry in pg_class for the relation. diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index 3f7ab8d389..8b8888af5e 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -34,9 +34,6 @@ #include "utils/rel.h" #include "utils/syscache.h" -/* Potentially set by pg_upgrade_support functions */ -Oid binary_upgrade_next_toast_pg_type_oid = InvalidOid; - static void CheckAndCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode, bool check); static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, @@ -135,7 +132,6 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Relation toast_rel; Relation class_rel; Oid toast_relid; - Oid toast_typid = InvalidOid; Oid namespaceid; char toast_relname[NAMEDATALEN]; char toast_idxname[NAMEDATALEN]; @@ -181,8 +177,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, * problem that it might take up an OID that will conflict with some * old-cluster table we haven't seen yet. */ - if (!OidIsValid(binary_upgrade_next_toast_pg_class_oid) || - !OidIsValid(binary_upgrade_next_toast_pg_type_oid)) + if (!OidIsValid(binary_upgrade_next_toast_pg_class_oid)) return false; } @@ -234,17 +229,6 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, else namespaceid = PG_TOAST_NAMESPACE; - /* - * Use binary-upgrade override for pg_type.oid, if supplied. We might be - * in the post-schema-restore phase where we are doing ALTER TABLE to - * create TOAST tables that didn't exist in the old cluster. - */ - if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_toast_pg_type_oid)) - { - toast_typid = binary_upgrade_next_toast_pg_type_oid; - binary_upgrade_next_toast_pg_type_oid = InvalidOid; - } - /* Toast table is shared if and only if its parent is. */ shared_relation = rel->rd_rel->relisshared; @@ -255,7 +239,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, namespaceid, rel->rd_rel->reltablespace, toastOid, - toast_typid, + InvalidOid, InvalidOid, rel->rd_rel->relowner, table_relation_toast_am(rel), diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index f79044f39f..42330692e7 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -11001,8 +11001,8 @@ ATPrepAlterColumnType(List **wqueue, tab->relkind == RELKIND_FOREIGN_TABLE) { /* - * For composite types, do this check now. Tables will check it later - * when the table is being rewritten. + * For composite types and foreign tables, do this check now. Regular + * tables will check it later when the table is being rewritten. */ find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL); } @@ -12564,8 +12564,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock /* * Also change the ownership of the table's row type, if it has one */ - if (tuple_class->relkind != RELKIND_INDEX && - tuple_class->relkind != RELKIND_PARTITIONED_INDEX) + if (OidIsValid(tuple_class->reltype)) AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId); /* @@ -15009,9 +15008,10 @@ AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid, AlterRelationNamespaceInternal(classRel, RelationGetRelid(rel), oldNspOid, nspOid, true, objsMoved); - /* Fix the table's row type too */ - AlterTypeNamespaceInternal(rel->rd_rel->reltype, - nspOid, false, false, objsMoved); + /* Fix the table's row type too, if it has one */ + if (OidIsValid(rel->rd_rel->reltype)) + AlterTypeNamespaceInternal(rel->rd_rel->reltype, + nspOid, false, false, objsMoved); /* Fix other dependent stuff */ if (rel->rd_rel->relkind == RELKIND_RELATION || @@ -15206,11 +15206,11 @@ AlterSeqNamespaces(Relation classRel, Relation rel, true, objsMoved); /* - * Sequences have entries in pg_type. We need to be careful to move - * them to the new namespace, too. + * Sequences used to have entries in pg_type, but no longer do. If we + * ever re-instate that, we'll need to move the pg_type entry to the + * new namespace, too (using AlterTypeNamespaceInternal). */ - AlterTypeNamespaceInternal(RelationGetForm(seqRel)->reltype, - newNspOid, false, false, objsMoved); + Assert(RelationGetForm(seqRel)->reltype == InvalidOid); /* Now we can close it. Keep the lock till end of transaction. */ relation_close(seqRel, NoLock); diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index b442b5a29e..49de285f01 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -145,8 +145,10 @@ makeWholeRowVar(RangeTblEntry *rte, /* relation: the rowtype is a named composite type */ toid = get_rel_type_id(rte->relid); if (!OidIsValid(toid)) - elog(ERROR, "could not find type OID for relation %u", - rte->relid); + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("relation \"%s\" does not have a composite type", + get_rel_name(rte->relid)))); result = makeVar(varno, InvalidAttrNumber, toid, diff --git a/src/backend/utils/adt/pg_upgrade_support.c b/src/backend/utils/adt/pg_upgrade_support.c index 18f2ee8226..14d9eb2b5b 100644 --- a/src/backend/utils/adt/pg_upgrade_support.c +++ b/src/backend/utils/adt/pg_upgrade_support.c @@ -51,17 +51,6 @@ binary_upgrade_set_next_array_pg_type_oid(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } -Datum -binary_upgrade_set_next_toast_pg_type_oid(PG_FUNCTION_ARGS) -{ - Oid typoid = PG_GETARG_OID(0); - - CHECK_IS_BINARY_UPGRADE; - binary_upgrade_next_toast_pg_type_oid = typoid; - - PG_RETURN_VOID(); -} - Datum binary_upgrade_set_next_heap_pg_class_oid(PG_FUNCTION_ARGS) { diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 0b9eb00d2d..a2453cf1f4 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -506,9 +506,10 @@ RelationBuildTupleDesc(Relation relation) AttrMissing *attrmiss = NULL; int ndef = 0; - /* copy some fields from pg_class row to rd_att */ - relation->rd_att->tdtypeid = relation->rd_rel->reltype; - relation->rd_att->tdtypmod = -1; /* unnecessary, but... */ + /* fill rd_att's type ID fields (compare heap.c's AddNewRelationTuple) */ + relation->rd_att->tdtypeid = + relation->rd_rel->reltype ? relation->rd_rel->reltype : RECORDOID; + relation->rd_att->tdtypmod = -1; /* just to be sure */ constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext, sizeof(TupleConstr)); @@ -1886,7 +1887,7 @@ formrdesc(const char *relationName, Oid relationReltype, relation->rd_att->tdrefcount = 1; /* mark as refcounted */ relation->rd_att->tdtypeid = relationReltype; - relation->rd_att->tdtypmod = -1; /* unnecessary, but... */ + relation->rd_att->tdtypmod = -1; /* just to be sure */ /* * initialize tuple desc info @@ -5692,8 +5693,8 @@ load_relcache_init_file(bool shared) rel->rd_att = CreateTemplateTupleDesc(relform->relnatts); rel->rd_att->tdrefcount = 1; /* mark as refcounted */ - rel->rd_att->tdtypeid = relform->reltype; - rel->rd_att->tdtypmod = -1; /* unnecessary, but... */ + rel->rd_att->tdtypeid = relform->reltype ? relform->reltype : RECORDOID; + rel->rd_att->tdtypmod = -1; /* just to be sure */ /* next read all the attribute tuple form data entries */ has_not_null = false; diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index a41a3db876..fd7b3e0920 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -272,7 +272,7 @@ static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout, PQExpBuffer upgrade_buffer, Oid pg_type_oid, bool force_array_type); -static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout, +static void binary_upgrade_set_type_oids_by_rel_oid(Archive *fout, PQExpBuffer upgrade_buffer, Oid pg_rel_oid); static void binary_upgrade_set_pg_class_oids(Archive *fout, PQExpBuffer upgrade_buffer, @@ -4493,7 +4493,7 @@ binary_upgrade_set_type_oids_by_type_oid(Archive *fout, destroyPQExpBuffer(upgrade_query); } -static bool +static void binary_upgrade_set_type_oids_by_rel_oid(Archive *fout, PQExpBuffer upgrade_buffer, Oid pg_rel_oid) @@ -4501,48 +4501,23 @@ binary_upgrade_set_type_oids_by_rel_oid(Archive *fout, PQExpBuffer upgrade_query = createPQExpBuffer(); PGresult *upgrade_res; Oid pg_type_oid; - bool toast_set = false; - /* - * We only support old >= 8.3 for binary upgrades. - * - * We purposefully ignore toast OIDs for partitioned tables; the reason is - * that versions 10 and 11 have them, but 12 does not, so emitting them - * causes the upgrade to fail. - */ appendPQExpBuffer(upgrade_query, - "SELECT c.reltype AS crel, t.reltype AS trel " + "SELECT c.reltype AS crel " "FROM pg_catalog.pg_class c " - "LEFT JOIN pg_catalog.pg_class t ON " - " (c.reltoastrelid = t.oid AND c.relkind <> '%c') " "WHERE c.oid = '%u'::pg_catalog.oid;", - RELKIND_PARTITIONED_TABLE, pg_rel_oid); + pg_rel_oid); upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data); pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel"))); - binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer, - pg_type_oid, false); - - if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel"))) - { - /* Toast tables do not have pg_type array rows */ - Oid pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0, - PQfnumber(upgrade_res, "trel"))); - - appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n"); - appendPQExpBuffer(upgrade_buffer, - "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n", - pg_type_toast_oid); - - toast_set = true; - } + if (OidIsValid(pg_type_oid)) + binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer, + pg_type_oid, false); PQclear(upgrade_res); destroyPQExpBuffer(upgrade_query); - - return toast_set; } static void @@ -17209,8 +17184,11 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) { binary_upgrade_set_pg_class_oids(fout, query, tbinfo->dobj.catId.oid, false); - binary_upgrade_set_type_oids_by_rel_oid(fout, query, - tbinfo->dobj.catId.oid); + + /* + * In older PG versions a sequence will have a pg_type entry, but v14 + * and up don't use that, so don't attempt to preserve the type OID. + */ } if (tbinfo->is_identity_sequence) diff --git a/src/include/catalog/binary_upgrade.h b/src/include/catalog/binary_upgrade.h index 12d94fe1b3..02fecb90f7 100644 --- a/src/include/catalog/binary_upgrade.h +++ b/src/include/catalog/binary_upgrade.h @@ -16,7 +16,6 @@ extern PGDLLIMPORT Oid binary_upgrade_next_pg_type_oid; extern PGDLLIMPORT Oid binary_upgrade_next_array_pg_type_oid; -extern PGDLLIMPORT Oid binary_upgrade_next_toast_pg_type_oid; extern PGDLLIMPORT Oid binary_upgrade_next_heap_pg_class_oid; extern PGDLLIMPORT Oid binary_upgrade_next_index_pg_class_oid; diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 1b35510d46..60e5361af6 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202007071 +#define CATALOG_VERSION_NO 202007072 #endif diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 3c89c53aa2..d951b4a36f 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -10306,10 +10306,6 @@ proname => 'binary_upgrade_set_next_array_pg_type_oid', provolatile => 'v', proparallel => 'r', prorettype => 'void', proargtypes => 'oid', prosrc => 'binary_upgrade_set_next_array_pg_type_oid' }, -{ oid => '3585', descr => 'for use by pg_upgrade', - proname => 'binary_upgrade_set_next_toast_pg_type_oid', provolatile => 'v', - proparallel => 'r', prorettype => 'void', proargtypes => 'oid', - prosrc => 'binary_upgrade_set_next_toast_pg_type_oid' }, { oid => '3586', descr => 'for use by pg_upgrade', proname => 'binary_upgrade_set_next_heap_pg_class_oid', provolatile => 'v', proparallel => 'r', prorettype => 'void', proargtypes => 'oid', diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 828ff5a288..e7f4a5f291 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -1778,6 +1778,7 @@ PLpgSQL_type * plpgsql_parse_wordrowtype(char *ident) { Oid classOid; + Oid typOid; /* * Look up the relation. Note that because relation rowtypes have the @@ -1792,8 +1793,16 @@ plpgsql_parse_wordrowtype(char *ident) (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation \"%s\" does not exist", ident))); + /* Some relkinds lack type OIDs */ + typOid = get_rel_type_id(classOid); + if (!OidIsValid(typOid)) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("relation \"%s\" does not have a composite type", + ident))); + /* Build and return the row type struct */ - return plpgsql_build_datatype(get_rel_type_id(classOid), -1, InvalidOid, + return plpgsql_build_datatype(typOid, -1, InvalidOid, makeTypeName(ident)); } @@ -1806,6 +1815,7 @@ PLpgSQL_type * plpgsql_parse_cwordrowtype(List *idents) { Oid classOid; + Oid typOid; RangeVar *relvar; MemoryContext oldCxt; @@ -1825,10 +1835,18 @@ plpgsql_parse_cwordrowtype(List *idents) -1); classOid = RangeVarGetRelid(relvar, NoLock, false); + /* Some relkinds lack type OIDs */ + typOid = get_rel_type_id(classOid); + if (!OidIsValid(typOid)) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("relation \"%s\" does not have a composite type", + strVal(lsecond(idents))))); + MemoryContextSwitchTo(oldCxt); /* Build and return the row type struct */ - return plpgsql_build_datatype(get_rel_type_id(classOid), -1, InvalidOid, + return plpgsql_build_datatype(typOid, -1, InvalidOid, makeTypeNameFromNameList(idents)); } -- 2.39.5