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
This commit is contained in:
Tom Lane 2020-07-07 15:43:22 -04:00
parent a8aaa0c786
commit f3faf35f37
12 changed files with 102 additions and 123 deletions

View File

@ -1895,7 +1895,8 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
</para>
<para>
The OID of the data type that corresponds to this table's row type,
if any (zero for indexes, which have no <structname>pg_type</structname> entry)
if any (zero for indexes, sequences, and toast tables, which have
no <structname>pg_type</structname> entry)
</para></entry>
</row>

View File

@ -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.

View File

@ -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),

View File

@ -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);

View File

@ -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,

View File

@ -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)
{

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 202007071
#define CATALOG_VERSION_NO 202007072
#endif

View File

@ -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',

View File

@ -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));
}