Convert Typ from array to list in bootstrap
authorTomas Vondra <tomas.vondra@postgresql.org>
Tue, 23 Mar 2021 23:47:38 +0000 (00:47 +0100)
committerTomas Vondra <tomas.vondra@postgresql.org>
Tue, 23 Mar 2021 23:47:40 +0000 (00:47 +0100)
It's a bit easier and more convenient to free and reload a List,
compared to a plain array. This will be helpful when allowing catalogs
to contain composite types.

Author: Justin Pryzby
Reviewed-by: Dean Rasheed, Tomas Vondra
Discussion: https://postgr.es/m/ad7891d2-e90c-b446-9fe2-7419143847d7%40enterprisedb.com

src/backend/bootstrap/bootstrap.c

index 99e5968ea4f23ac831da55f36eb8d0698f94a53a..52d36ae1a2889879356d2d733a87da3dbd1a4ee7 100644 (file)
@@ -59,7 +59,7 @@ static void BootstrapModeMain(void);
 static void bootstrap_signals(void);
 static void ShutdownAuxiliaryProcess(int code, Datum arg);
 static Form_pg_attribute AllocateAttribute(void);
-static void populate_typ_array(void);
+static void populate_typ_list(void);
 static Oid     gettype(char *type);
 static void cleanup(void);
 
@@ -160,7 +160,7 @@ struct typmap
        FormData_pg_type am_typ;
 };
 
-static struct typmap **Typ = NULL;
+static List *Typ = NIL; /* List of struct typmap* */
 static struct typmap *Ap = NULL;
 
 static Datum values[MAXATTR];  /* current row's attribute values */
@@ -598,10 +598,10 @@ boot_openrel(char *relname)
 
        /*
         * pg_type must be filled before any OPEN command is executed, hence we
-        * can now populate the Typ array if we haven't yet.
+        * can now populate Typ if we haven't yet.
         */
-       if (Typ == NULL)
-               populate_typ_array();
+       if (Typ == NIL)
+               populate_typ_list();
 
        if (boot_reldesc != NULL)
                closerel(NULL);
@@ -691,7 +691,7 @@ DefineAttr(char *name, char *type, int attnum, int nullness)
 
        typeoid = gettype(type);
 
-       if (Typ != NULL)
+       if (Typ != NIL)
        {
                attrtypes[attnum]->atttypid = Ap->am_oid;
                attrtypes[attnum]->attlen = Ap->am_typ.typlen;
@@ -873,47 +873,36 @@ cleanup(void)
 }
 
 /* ----------------
- *             populate_typ_array
+ *             populate_typ_list
  *
- * Load the Typ array by reading pg_type.
+ * Load the Typ list by reading pg_type.
  * ----------------
  */
 static void
-populate_typ_array(void)
+populate_typ_list(void)
 {
        Relation        rel;
        TableScanDesc scan;
        HeapTuple       tup;
-       int                     nalloc;
-       int                     i;
-
-       Assert(Typ == NULL);
+       MemoryContext old;
 
-       nalloc = 512;
-       Typ = (struct typmap **)
-               MemoryContextAlloc(TopMemoryContext, nalloc * sizeof(struct typmap *));
+       Assert(Typ == NIL);
 
        rel = table_open(TypeRelationId, NoLock);
        scan = table_beginscan_catalog(rel, 0, NULL);
-       i = 0;
+       old = MemoryContextSwitchTo(TopMemoryContext);
        while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
        {
                Form_pg_type typForm = (Form_pg_type) GETSTRUCT(tup);
+               struct typmap *newtyp;
 
-               /* make sure there will be room for a trailing NULL pointer */
-               if (i >= nalloc - 1)
-               {
-                       nalloc *= 2;
-                       Typ = (struct typmap **)
-                               repalloc(Typ, nalloc * sizeof(struct typmap *));
-               }
-               Typ[i] = (struct typmap *)
-                       MemoryContextAlloc(TopMemoryContext, sizeof(struct typmap));
-               Typ[i]->am_oid = typForm->oid;
-               memcpy(&(Typ[i]->am_typ), typForm, sizeof(Typ[i]->am_typ));
-               i++;
+               newtyp = (struct typmap *) palloc(sizeof(struct typmap));
+               Typ = lappend(Typ, newtyp);
+
+               newtyp->am_oid = typForm->oid;
+               memcpy(&newtyp->am_typ, typForm, sizeof(newtyp->am_typ));
        }
-       Typ[i] = NULL;                          /* Fill trailing NULL pointer */
+       MemoryContextSwitchTo(old);
        table_endscan(scan);
        table_close(rel, NoLock);
 }
@@ -923,25 +912,26 @@ populate_typ_array(void)
  *
  * NB: this is really ugly; it will return an integer index into TypInfo[],
  * and not an OID at all, until the first reference to a type not known in
- * TypInfo[].  At that point it will read and cache pg_type in the Typ array,
+ * TypInfo[].  At that point it will read and cache pg_type in Typ,
  * and subsequently return a real OID (and set the global pointer Ap to
  * point at the found row in Typ).  So caller must check whether Typ is
- * still NULL to determine what the return value is!
+ * still NIL to determine what the return value is!
  * ----------------
  */
 static Oid
 gettype(char *type)
 {
-       if (Typ != NULL)
+       if (Typ != NIL)
        {
-               struct typmap **app;
+               ListCell *lc;
 
-               for (app = Typ; *app != NULL; app++)
+               foreach (lc, Typ)
                {
-                       if (strncmp(NameStr((*app)->am_typ.typname), type, NAMEDATALEN) == 0)
+                       struct typmap *app = lfirst(lc);
+                       if (strncmp(NameStr(app->am_typ.typname), type, NAMEDATALEN) == 0)
                        {
-                               Ap = *app;
-                               return (*app)->am_oid;
+                               Ap = app;
+                               return app->am_oid;
                        }
                }
        }
@@ -956,7 +946,7 @@ gettype(char *type)
                }
                /* Not in TypInfo, so we'd better be able to read pg_type now */
                elog(DEBUG4, "external type: %s", type);
-               populate_typ_array();
+               populate_typ_list();
                return gettype(type);
        }
        elog(ERROR, "unrecognized type \"%s\"", type);
@@ -984,17 +974,20 @@ boot_get_type_io_data(Oid typid,
                                          Oid *typinput,
                                          Oid *typoutput)
 {
-       if (Typ != NULL)
+       if (Typ != NIL)
        {
                /* We have the boot-time contents of pg_type, so use it */
-               struct typmap **app;
-               struct typmap *ap;
-
-               app = Typ;
-               while (*app && (*app)->am_oid != typid)
-                       ++app;
-               ap = *app;
-               if (ap == NULL)
+               struct typmap *ap = NULL;
+               ListCell *lc;
+
+               foreach (lc, Typ)
+               {
+                       ap = lfirst(lc);
+                       if (ap->am_oid == typid)
+                               break;
+               }
+
+               if (!ap || ap->am_oid != typid)
                        elog(ERROR, "type OID %u not found in Typ list", typid);
 
                *typlen = ap->am_typ.typlen;