Convert Typ from array to list in bootstrap

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
This commit is contained in:
Tomas Vondra 2021-03-24 00:47:38 +01:00
parent 5b861baa55
commit e1a5e65703
1 changed files with 40 additions and 47 deletions

View 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;
MemoryContext old;
Assert(Typ == NULL);
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;
struct typmap *ap = NULL;
ListCell *lc;
app = Typ;
while (*app && (*app)->am_oid != typid)
++app;
ap = *app;
if (ap == NULL)
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;