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);
 
