diff --git a/src/pl/plpython/plpy_cursorobject.c b/src/pl/plpython/plpy_cursorobject.c
index 2c458d3..8de2b1e 100644
--- a/src/pl/plpython/plpy_cursorobject.c
+++ b/src/pl/plpython/plpy_cursorobject.c
@@ -8,6 +8,7 @@
 
 #include "access/xact.h"
 #include "mb/pg_wchar.h"
+#include "utils/memutils.h"
 
 #include "plpython.h"
 
@@ -111,7 +112,7 @@ PLy_cursor_query(const char *query)
 		return NULL;
 	cursor->portalname = NULL;
 	cursor->closed = false;
-	PLy_typeinfo_init(&cursor->result);
+	PLy_typeinfo_init(&cursor->result, TopMemoryContext);
 
 	oldcontext = CurrentMemoryContext;
 	oldowner = CurrentResourceOwner;
@@ -200,7 +201,7 @@ PLy_cursor_plan(PyObject *ob, PyObject *args)
 		return NULL;
 	cursor->portalname = NULL;
 	cursor->closed = false;
-	PLy_typeinfo_init(&cursor->result);
+	PLy_typeinfo_init(&cursor->result, TopMemoryContext);
 
 	oldcontext = CurrentMemoryContext;
 	oldowner = CurrentResourceOwner;
diff --git a/src/pl/plpython/plpy_procedure.c b/src/pl/plpython/plpy_procedure.c
index 16ff845..32972d9 100644
--- a/src/pl/plpython/plpy_procedure.c
+++ b/src/pl/plpython/plpy_procedure.c
@@ -164,9 +164,9 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger)
 	/* Remember if function is STABLE/IMMUTABLE */
 	proc->fn_readonly =
 		(procStruct->provolatile != PROVOLATILE_VOLATILE);
-	PLy_typeinfo_init(&proc->result);
+	PLy_typeinfo_init(&proc->result, TopMemoryContext);
 	for (i = 0; i < FUNC_MAX_ARGS; i++)
-		PLy_typeinfo_init(&proc->args[i]);
+		PLy_typeinfo_init(&proc->args[i], TopMemoryContext);
 	proc->nargs = 0;
 	proc->langid = procStruct->prolang;
 	{
diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c
index d0e255f..e552239 100644
--- a/src/pl/plpython/plpy_spi.c
+++ b/src/pl/plpython/plpy_spi.c
@@ -84,7 +84,7 @@ PLy_spi_prepare(PyObject *self, PyObject *args)
 		 */
 		for (i = 0; i < nargs; i++)
 		{
-			PLy_typeinfo_init(&plan->args[i]);
+			PLy_typeinfo_init(&plan->args[i], TopMemoryContext);
 			plan->values[i] = PointerGetDatum(NULL);
 		}
 
@@ -394,7 +394,7 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
 
 		Py_DECREF(result->nrows);
 		result->nrows = PyInt_FromLong(rows);
-		PLy_typeinfo_init(&args);
+		PLy_typeinfo_init(&args, CurrentMemoryContext);
 
 		oldcontext = CurrentMemoryContext;
 		PG_TRY();
diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c
index 7a45b22..4421cf9 100644
--- a/src/pl/plpython/plpy_typeio.c
+++ b/src/pl/plpython/plpy_typeio.c
@@ -29,8 +29,8 @@
 
 
 /* I/O function caching */
-static void PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes);
-static void PLy_output_datum_func2(PLyObToDatum *arg, HeapTuple typeTup, Oid langid, List *trftypes);
+static void PLy_input_datum_func2(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes);
+static void PLy_output_datum_func2(PLyObToDatum *arg, MemoryContext arg_mcxt, HeapTuple typeTup, Oid langid, List *trftypes);
 
 /* conversion from Datums to Python objects */
 static PyObject *PLyBool_FromBool(PLyDatumToOb *arg, Datum d);
@@ -60,11 +60,8 @@ static Datum PLyMapping_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject
 static Datum PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence);
 static Datum PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object);
 
-/* make allocations in the TopMemoryContext */
-static void perm_fmgr_info(Oid functionId, FmgrInfo *finfo);
-
 void
-PLy_typeinfo_init(PLyTypeInfo *arg)
+PLy_typeinfo_init(PLyTypeInfo *arg, MemoryContext mcxt)
 {
 	arg->is_rowtype = -1;
 	arg->in.r.natts = arg->out.r.natts = 0;
@@ -73,6 +70,7 @@ PLy_typeinfo_init(PLyTypeInfo *arg)
 	arg->typ_relid = InvalidOid;
 	arg->typrel_xmin = InvalidTransactionId;
 	ItemPointerSetInvalid(&arg->typrel_tid);
+	arg->mcxt = mcxt;
 }
 
 void
@@ -109,7 +107,7 @@ PLy_input_datum_func(PLyTypeInfo *arg, Oid typeOid, HeapTuple typeTup, Oid langi
 	if (arg->is_rowtype > 0)
 		elog(ERROR, "PLyTypeInfo struct is initialized for Tuple");
 	arg->is_rowtype = 0;
-	PLy_input_datum_func2(&(arg->in.d), typeOid, typeTup, langid, trftypes);
+	PLy_input_datum_func2(&(arg->in.d), arg->mcxt, typeOid, typeTup, langid, trftypes);
 }
 
 void
@@ -118,7 +116,7 @@ PLy_output_datum_func(PLyTypeInfo *arg, HeapTuple typeTup, Oid langid, List *trf
 	if (arg->is_rowtype > 0)
 		elog(ERROR, "PLyTypeInfo struct is initialized for a Tuple");
 	arg->is_rowtype = 0;
-	PLy_output_datum_func2(&(arg->out.d), typeTup, langid, trftypes);
+	PLy_output_datum_func2(&(arg->out.d), arg->mcxt, typeTup, langid, trftypes);
 }
 
 void
@@ -182,7 +180,7 @@ PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
 			elog(ERROR, "cache lookup failed for type %u",
 				 desc->attrs[i]->atttypid);
 
-		PLy_input_datum_func2(&(arg->in.r.atts[i]),
+		PLy_input_datum_func2(&(arg->in.r.atts[i]), arg->mcxt,
 							  desc->attrs[i]->atttypid,
 							  typeTup,
 							  exec_ctx->curr_proc->langid,
@@ -249,7 +247,7 @@ PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc)
 			elog(ERROR, "cache lookup failed for type %u",
 				 desc->attrs[i]->atttypid);
 
-		PLy_output_datum_func2(&(arg->out.r.atts[i]), typeTup,
+		PLy_output_datum_func2(&(arg->out.r.atts[i]), arg->mcxt, typeTup,
 							   exec_ctx->curr_proc->langid,
 							   exec_ctx->curr_proc->trftypes);
 
@@ -370,14 +368,14 @@ PLyObject_ToCompositeDatum(PLyTypeInfo *info, TupleDesc desc, PyObject *plrv)
 }
 
 static void
-PLy_output_datum_func2(PLyObToDatum *arg, HeapTuple typeTup, Oid langid, List *trftypes)
+PLy_output_datum_func2(PLyObToDatum *arg, MemoryContext arg_mcxt, HeapTuple typeTup, Oid langid, List *trftypes)
 {
 	Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
 	Oid			element_type;
 	Oid			base_type;
 	Oid			funcid;
 
-	perm_fmgr_info(typeStruct->typinput, &arg->typfunc);
+	fmgr_info_cxt(typeStruct->typinput, &arg->typfunc, arg_mcxt);
 	arg->typoid = HeapTupleGetOid(typeTup);
 	arg->typmod = -1;
 	arg->typioparam = getTypeIOParam(typeTup);
@@ -394,7 +392,7 @@ PLy_output_datum_func2(PLyObToDatum *arg, HeapTuple typeTup, Oid langid, List *t
 	if ((funcid = get_transform_tosql(base_type, langid, trftypes)))
 	{
 		arg->func = PLyObject_ToTransform;
-		perm_fmgr_info(funcid, &arg->typtransform);
+		fmgr_info_cxt(funcid, &arg->typtransform, arg_mcxt);
 	}
 	else if (typeStruct->typtype == TYPTYPE_COMPOSITE)
 	{
@@ -432,12 +430,12 @@ PLy_output_datum_func2(PLyObToDatum *arg, HeapTuple typeTup, Oid langid, List *t
 		get_type_io_data(element_type, IOFunc_input,
 						 &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim,
 						 &arg->elm->typioparam, &funcid);
-		perm_fmgr_info(funcid, &arg->elm->typfunc);
+		fmgr_info_cxt(funcid, &arg->elm->typfunc, arg_mcxt);
 	}
 }
 
 static void
-PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes)
+PLy_input_datum_func2(PLyDatumToOb *arg, MemoryContext arg_mcxt, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes)
 {
 	Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
 	Oid			element_type;
@@ -445,7 +443,7 @@ PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup, Oid lan
 	Oid			funcid;
 
 	/* Get the type's conversion information */
-	perm_fmgr_info(typeStruct->typoutput, &arg->typfunc);
+	fmgr_info_cxt(typeStruct->typoutput, &arg->typfunc, arg_mcxt);
 	arg->typoid = HeapTupleGetOid(typeTup);
 	arg->typmod = -1;
 	arg->typioparam = getTypeIOParam(typeTup);
@@ -461,7 +459,7 @@ PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup, Oid lan
 	if ((funcid = get_transform_fromsql(base_type, langid, trftypes)))
 	{
 		arg->func = PLyObject_FromTransform;
-		perm_fmgr_info(funcid, &arg->typtransform);
+		fmgr_info_cxt(funcid, &arg->typtransform, arg_mcxt);
 	}
 	else
 		switch (base_type)
@@ -512,7 +510,7 @@ PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup, Oid lan
 		get_type_io_data(element_type, IOFunc_output,
 						 &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim,
 						 &arg->elm->typioparam, &funcid);
-		perm_fmgr_info(funcid, &arg->elm->typfunc);
+		fmgr_info_cxt(funcid, &arg->elm->typfunc, arg_mcxt);
 	}
 }
 
@@ -758,7 +756,7 @@ PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
 
 	/* Create a dummy PLyTypeInfo */
 	MemSet(&info, 0, sizeof(PLyTypeInfo));
-	PLy_typeinfo_init(&info);
+	PLy_typeinfo_init(&info, CurrentMemoryContext);
 	/* Mark it as needing output routines lookup */
 	info.is_rowtype = 2;
 
@@ -919,7 +917,7 @@ PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string)
 	if (!HeapTupleIsValid(typeTup))
 		elog(ERROR, "cache lookup failed for type %u", desc->tdtypeid);
 
-	PLy_output_datum_func2(&info->out.d, typeTup,
+	PLy_output_datum_func2(&info->out.d, info->mcxt, typeTup,
 						   exec_ctx->curr_proc->langid,
 						   exec_ctx->curr_proc->trftypes);
 
@@ -1168,19 +1166,3 @@ PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object
 	return result;
 }
 
-/*
- * This routine is a crock, and so is everyplace that calls it.  The problem
- * is that the cached form of plpython functions/queries is allocated permanently
- * (mostly via malloc()) and never released until backend exit.  Subsidiary
- * data structures such as fmgr info records therefore must live forever
- * as well.  A better implementation would store all this stuff in a per-
- * function memory context that could be reclaimed at need.  In the meantime,
- * fmgr_info_cxt must be called specifying TopMemoryContext so that whatever
- * it might allocate, and whatever the eventual function might allocate using
- * fn_mcxt, will live forever too.
- */
-static void
-perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
-{
-	fmgr_info_cxt(functionId, finfo, TopMemoryContext);
-}
diff --git a/src/pl/plpython/plpy_typeio.h b/src/pl/plpython/plpy_typeio.h
index b01151b..6300970 100644
--- a/src/pl/plpython/plpy_typeio.h
+++ b/src/pl/plpython/plpy_typeio.h
@@ -88,9 +88,11 @@ typedef struct PLyTypeInfo
 	Oid			typ_relid;
 	TransactionId typrel_xmin;
 	ItemPointerData typrel_tid;
+
+	MemoryContext mcxt;
 } PLyTypeInfo;
 
-extern void PLy_typeinfo_init(PLyTypeInfo *arg);
+extern void PLy_typeinfo_init(PLyTypeInfo *arg, MemoryContext mcxt);
 extern void PLy_typeinfo_dealloc(PLyTypeInfo *arg);
 
 extern void PLy_input_datum_func(PLyTypeInfo *arg, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes);
