Convert Typ from array to list in bootstrap
authorTomas Vondra <[email protected]>
Tue, 23 Mar 2021 23:47:38 +0000 (00:47 +0100)
committerTomas Vondra <[email protected]>
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;