I noticed while going over the multirange types patch that it adds a pointless typiofunc cached OID to a struct used for I/O functions' fn_extra. It seems to go completely unused, so I checked range types (which this was cribbed from) and indeed, it is completely unused there either. My guess is that it was in turn cribbed from array's ArrayMetaState, which is considerably more sophisticated; I suspect nobody noticed that caching it was pointless.
Here's a patch to remove it from rangetypes.c. It doesn't really waste much memory anyway, but removing it lessens the cognitive load by one or two bits. -- Álvaro Herrera
diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c index 490bc2ae81..412322c6fa 100644 --- a/src/backend/utils/adt/rangetypes.c +++ b/src/backend/utils/adt/rangetypes.c @@ -49,7 +49,6 @@ typedef struct RangeIOData { TypeCacheEntry *typcache; /* range type's typcache entry */ - Oid typiofunc; /* element type's I/O function */ Oid typioparam; /* element type's I/O parameter */ FmgrInfo proc; /* lookup result for typiofunc */ } RangeIOData; @@ -309,6 +308,7 @@ get_range_io_data(FunctionCallInfo fcinfo, Oid rngtypid, IOFuncSelector func) bool typbyval; char typalign; char typdelim; + Oid typiofunc; cache = (RangeIOData *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(RangeIOData)); @@ -324,9 +324,9 @@ get_range_io_data(FunctionCallInfo fcinfo, Oid rngtypid, IOFuncSelector func) &typalign, &typdelim, &cache->typioparam, - &cache->typiofunc); + &typiofunc); - if (!OidIsValid(cache->typiofunc)) + if (!OidIsValid(typiofunc)) { /* this could only happen for receive or send */ if (func == IOFunc_receive) @@ -340,7 +340,7 @@ get_range_io_data(FunctionCallInfo fcinfo, Oid rngtypid, IOFuncSelector func) errmsg("no binary output function available for type %s", format_type_be(cache->typcache->rngelemtype->type_id)))); } - fmgr_info_cxt(cache->typiofunc, &cache->proc, + fmgr_info_cxt(typiofunc, &cache->proc, fcinfo->flinfo->fn_mcxt); fcinfo->flinfo->fn_extra = (void *) cache;