Re: [bug] Table not have typarray when created by single user mode - Mailing list pgsql-bugs

From Tom Lane
Subject Re: [bug] Table not have typarray when created by single user mode
Date
Msg-id 1468768.1594066959@sss.pgh.pa.us
Whole thread Raw
In response to Re: [bug] Table not have typarray when created by single user mode  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: [bug] Table not have typarray when created by single user mode
List pgsql-bugs
I wrote:
> However, if we're going to go this far, I think there's a good
> case to be made for going all the way and eliminating the policy
> of not making array types for system catalogs.  That was never
> anything but a wart justified by space savings in pg_type, and
> this patch already kills most of the space savings.  If we
> drop the system-state test in heap_create_with_catalog altogether,
> we end up with 601 initial pg_type entries.  That still leaves
> the four bootstrap catalogs without array types, because they are
> not created by heap_create_with_catalog; but we can manually add
> those too for a total of 605 initial entries.  (That brings initial
> pg_type to 14 pages as I show above; I think it was 13 with the
> original version of the patch.)
> In short, if we're gonna do this, I think we should do it like
> the attached.  Or we could do nothing, but there is some appeal
> to removing this old inconsistency.

I pushed that, but while working on it I had a further thought:
why is it that we create composite types but not arrays over those
types for *any* relkinds?  That is, we could create even more
consistency, as well as buying back some of the pg_type bloat added
here, by not creating pg_type entries at all for toast tables or
sequences.  A little bit of hacking later, I have the attached.

One could argue it either way as to whether sequences should have
composite types.  It's possible to demonstrate queries that will
fail without one:

regression=# create sequence seq1;
CREATE SEQUENCE
regression=# select s from seq1 s;
ERROR:  relation "seq1" does not have a composite type

but it's pretty hard to believe anyone's using that in practice.
Also, we've talked more than once about changing the implementation
of sequences to not have a relation per sequence, in which case the
ability to do something like the above would go away anyway.

Comments?

            regards, tom lane

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 003d278370..7471ba53f2 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1895,7 +1895,8 @@ SCRAM-SHA-256$<replaceable><iteration count></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>

diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index fd04e82b20..ae509d9d49 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1118,8 +1118,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 +1260,45 @@ 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();
+
+        /*
+         * 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 +1335,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..4b2548f33f 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -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/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index a41a3db876..ee0947dda7 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
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/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 38295aca48..a995a104b6 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));
 }


pgsql-bugs by date:

Previous
From: Tom Lane
Date:
Subject: Re: BUG #16528: Analytical function with Over clause for ARRAY datatype is not working properly
Next
From: Soumyadeep Chakraborty
Date:
Subject: Re: posgres 12 bug (partitioned table)