diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c index 097dd73..8e745c3 100644 --- a/src/backend/utils/adt/array_userfuncs.c +++ b/src/backend/utils/adt/array_userfuncs.c @@ -21,6 +21,25 @@ #include "utils/lsyscache.h" #include "utils/typcache.h" +/* + * DeserialIOData + * Used for caching type data in array deserial function + */ +typedef struct DeserialIOData +{ + Oid typreceive; + Oid typioparam; +} DeserialIOData; + +/* + * SerialIOData + * Used for caching type data in array serial function + */ +typedef struct SerialIOData +{ + Oid typsend; + bool typisvarlena; +} SerialIOData; static Datum array_position_common(FunctionCallInfo fcinfo); @@ -626,17 +645,29 @@ array_agg_serialize(PG_FUNCTION_ARGS) pq_sendbytes(&buf, (char *) state->dvalues, sizeof(Datum) * state->nelems); else { - Oid typsend; - bool typisvarlena; + SerialIOData *iodata; bytea *outputbytes; int i; - /* XXX is there anywhere to cache this to save calling each time? */ - getTypeBinaryOutputInfo(state->element_type, &typsend, &typisvarlena); + /* + * To avoid having to constantly make calls to getTypeBinaryOutputInfo + * we'll cache that information in fn_extra for the next call. Let's + * see if we've done that already... + */ + if (fcinfo->flinfo->fn_extra) + iodata = (SerialIOData *) fcinfo->flinfo->fn_extra; + else + { + fcinfo->flinfo->fn_extra = iodata = + MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, + sizeof(SerialIOData)); + getTypeBinaryOutputInfo(state->element_type, &iodata->typsend, + &iodata->typisvarlena); + } for (i = 0; i < state->nelems; i++) { - outputbytes = OidSendFunctionCall(typsend, state->dvalues[i]); + outputbytes = OidSendFunctionCall(iodata->typsend, state->dvalues[i]); pq_sendint32(&buf, VARSIZE(outputbytes) - VARHDRSZ); pq_sendbytes(&buf, VARDATA(outputbytes), VARSIZE(outputbytes) - VARHDRSZ); @@ -706,25 +737,40 @@ array_agg_deserialize(PG_FUNCTION_ARGS) } else { - Oid typreceive; - Oid typioparam; + DeserialIOData *iodata; int i; - getTypeBinaryInputInfo(element_type, &typreceive, &typioparam); + /* + * To avoid having to constantly make calls to getTypeBinaryInputInfo + * we'll cache that information in fn_extra for the next call. Let's + * see if we've done that already... + */ + if (fcinfo->flinfo->fn_extra) + iodata = (DeserialIOData *) fcinfo->flinfo->fn_extra; + else + { + fcinfo->flinfo->fn_extra = iodata = + MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, + sizeof(DeserialIOData)); + getTypeBinaryInputInfo(element_type, &iodata->typreceive, + &iodata->typioparam); + } for (i = 0; i < nelems; i++) { - /* XXX? Surely this cannot be the way to do this? */ StringInfoData tmp; tmp.cursor = 0; tmp.maxlen = tmp.len = pq_getmsgint(&buf, 4); tmp.data = (char *) pq_getmsgbytes(&buf, tmp.len); - result->dvalues[i] = OidReceiveFunctionCall(typreceive, &tmp, - typioparam, -1); + result->dvalues[i] = OidReceiveFunctionCall(iodata->typreceive, + &tmp, + iodata->typioparam, + -1); } } + /* dnulls */ temp = pq_getmsgbytes(&buf, sizeof(bool) * nelems); memcpy(result->dnulls, temp, sizeof(bool) * nelems);