*** a/src/pl/plpython/plpy_cursorobject.c
--- b/src/pl/plpython/plpy_cursorobject.c
***************
*** 8,13 ****
--- 8,14 ----
  
  #include "access/xact.h"
  #include "mb/pg_wchar.h"
+ #include "utils/memutils.h"
  
  #include "plpython.h"
  
***************
*** 111,117 **** PLy_cursor_query(const char *query)
  		return NULL;
  	cursor->portalname = NULL;
  	cursor->closed = false;
- 	PLy_typeinfo_init(&cursor->result);
  
  	oldcontext = CurrentMemoryContext;
  	oldowner = CurrentResourceOwner;
--- 112,117 ----
***************
*** 123,128 **** PLy_cursor_query(const char *query)
--- 123,130 ----
  		PLyExecutionContext *exec_ctx = PLy_current_execution_context();
  		SPIPlanPtr	plan;
  		Portal		portal;
+ 		
+ 		PLy_typeinfo_init(&cursor->result, exec_ctx->scratch_ctx);
  
  		pg_verifymbstr(query, strlen(query), false);
  
***************
*** 200,206 **** PLy_cursor_plan(PyObject *ob, PyObject *args)
  		return NULL;
  	cursor->portalname = NULL;
  	cursor->closed = false;
- 	PLy_typeinfo_init(&cursor->result);
  
  	oldcontext = CurrentMemoryContext;
  	oldowner = CurrentResourceOwner;
--- 202,207 ----
***************
*** 213,218 **** PLy_cursor_plan(PyObject *ob, PyObject *args)
--- 214,221 ----
  		Portal		portal;
  		char	   *volatile nulls;
  		volatile int j;
+ 		
+ 		PLy_typeinfo_init(&cursor->result, exec_ctx->scratch_ctx);
  
  		if (nargs > 0)
  			nulls = palloc(nargs * sizeof(char));
*** a/src/pl/plpython/plpy_procedure.c
--- b/src/pl/plpython/plpy_procedure.c
***************
*** 130,135 **** PLy_procedure_get(Oid fn_oid, Oid fn_rel, bool is_trigger)
--- 130,136 ----
  
  	ReleaseSysCache(procTup);
  
+ 	MemoryContextReset(proc->mcxt);
  	return proc;
  }
  
***************
*** 164,172 **** 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);
  	for (i = 0; i < FUNC_MAX_ARGS; i++)
! 		PLy_typeinfo_init(&proc->args[i]);
  	proc->nargs = 0;
  	proc->langid = procStruct->prolang;
  	{
--- 165,180 ----
  	/* Remember if function is STABLE/IMMUTABLE */
  	proc->fn_readonly =
  		(procStruct->provolatile != PROVOLATILE_VOLATILE);
! 
! 	proc->mcxt = AllocSetContextCreate(TopMemoryContext,
! 					 "PLY Type Info",
! 					 ALLOCSET_SMALL_MINSIZE,
! 					 ALLOCSET_SMALL_INITSIZE,
! 					 ALLOCSET_SMALL_MAXSIZE);
! 
! 	PLy_typeinfo_init(&proc->result, proc->mcxt);
  	for (i = 0; i < FUNC_MAX_ARGS; i++)
! 		PLy_typeinfo_init(&proc->args[i], proc->mcxt);
  	proc->nargs = 0;
  	proc->langid = procStruct->prolang;
  	{
***************
*** 413,418 **** PLy_procedure_delete(PLyProcedure *proc)
--- 421,428 ----
  		PLy_free(proc->proname);
  	if (proc->pyname)
  		PLy_free(proc->pyname);
+ 	if (proc->trftypes)
+ 		list_free_deep(proc->trftypes);
  	for (i = 0; i < proc->nargs; i++)
  	{
  		if (proc->args[i].is_rowtype == 1)
***************
*** 429,434 **** PLy_procedure_delete(PLyProcedure *proc)
--- 439,446 ----
  		PLy_free(proc->src);
  	if (proc->argnames)
  		PLy_free(proc->argnames);
+ 	if (proc->mcxt)
+ 		MemoryContextDelete(proc->mcxt);
  }
  
  /*
*** a/src/pl/plpython/plpy_procedure.h
--- b/src/pl/plpython/plpy_procedure.h
***************
*** 32,37 **** typedef struct PLyProcedure
--- 32,38 ----
  	PyObject   *code;			/* compiled procedure code */
  	PyObject   *statics;		/* data saved across calls, local scope */
  	PyObject   *globals;		/* data saved across calls, global scope */
+ 	MemoryContext mcxt;		/* context used to store PLY types */
  } PLyProcedure;
  
  /* the procedure cache key */
*** a/src/pl/plpython/plpy_spi.c
--- b/src/pl/plpython/plpy_spi.c
***************
*** 84,90 **** PLy_spi_prepare(PyObject *self, PyObject *args)
  		 */
  		for (i = 0; i < nargs; i++)
  		{
! 			PLy_typeinfo_init(&plan->args[i]);
  			plan->values[i] = PointerGetDatum(NULL);
  		}
  
--- 84,90 ----
  		 */
  		for (i = 0; i < nargs; i++)
  		{
! 			PLy_typeinfo_init(&plan->args[i], exec_ctx->scratch_ctx);
  			plan->values[i] = PointerGetDatum(NULL);
  		}
  
***************
*** 394,400 **** PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
  
  		Py_DECREF(result->nrows);
  		result->nrows = PyInt_FromLong(rows);
! 		PLy_typeinfo_init(&args);
  
  		oldcontext = CurrentMemoryContext;
  		PG_TRY();
--- 394,400 ----
  
  		Py_DECREF(result->nrows);
  		result->nrows = PyInt_FromLong(rows);
! 		PLy_typeinfo_init(&args, CurrentMemoryContext);
  
  		oldcontext = CurrentMemoryContext;
  		PG_TRY();
*** a/src/pl/plpython/plpy_typeio.c
--- b/src/pl/plpython/plpy_typeio.c
***************
*** 29,36 ****
  
  
  /* 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);
  
  /* conversion from Datums to Python objects */
  static PyObject *PLyBool_FromBool(PLyDatumToOb *arg, Datum d);
--- 29,36 ----
  
  
  /* I/O function caching */
! 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,70 **** 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)
  {
  	arg->is_rowtype = -1;
  	arg->in.r.natts = arg->out.r.natts = 0;
--- 60,67 ----
  static Datum PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence);
  static Datum PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object);
  
  void
! PLy_typeinfo_init(PLyTypeInfo *arg, MemoryContext mcxt)
  {
  	arg->is_rowtype = -1;
  	arg->in.r.natts = arg->out.r.natts = 0;
***************
*** 73,78 **** PLy_typeinfo_init(PLyTypeInfo *arg)
--- 70,76 ----
  	arg->typ_relid = InvalidOid;
  	arg->typrel_xmin = InvalidTransactionId;
  	ItemPointerSetInvalid(&arg->typrel_tid);
+ 	arg->mcxt = mcxt;
  }
  
  void
***************
*** 109,115 **** 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);
  }
  
  void
--- 107,113 ----
  	if (arg->is_rowtype > 0)
  		elog(ERROR, "PLyTypeInfo struct is initialized for Tuple");
  	arg->is_rowtype = 0;
! 	PLy_input_datum_func2(&(arg->in.d), arg->mcxt, typeOid, typeTup, langid, trftypes);
  }
  
  void
***************
*** 118,124 **** 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);
  }
  
  void
--- 116,122 ----
  	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), arg->mcxt, typeTup, langid, trftypes);
  }
  
  void
***************
*** 182,188 **** 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]),
  							  desc->attrs[i]->atttypid,
  							  typeTup,
  							  exec_ctx->curr_proc->langid,
--- 180,186 ----
  			elog(ERROR, "cache lookup failed for type %u",
  				 desc->attrs[i]->atttypid);
  
! 		PLy_input_datum_func2(&(arg->in.r.atts[i]), arg->mcxt,
  							  desc->attrs[i]->atttypid,
  							  typeTup,
  							  exec_ctx->curr_proc->langid,
***************
*** 249,255 **** 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,
  							   exec_ctx->curr_proc->langid,
  							   exec_ctx->curr_proc->trftypes);
  
--- 247,253 ----
  			elog(ERROR, "cache lookup failed for type %u",
  				 desc->attrs[i]->atttypid);
  
! 		PLy_output_datum_func2(&(arg->out.r.atts[i]), arg->mcxt, typeTup,
  							   exec_ctx->curr_proc->langid,
  							   exec_ctx->curr_proc->trftypes);
  
***************
*** 370,383 **** PLyObject_ToCompositeDatum(PLyTypeInfo *info, TupleDesc desc, PyObject *plrv)
  }
  
  static void
! PLy_output_datum_func2(PLyObToDatum *arg, 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);
  	arg->typoid = HeapTupleGetOid(typeTup);
  	arg->typmod = -1;
  	arg->typioparam = getTypeIOParam(typeTup);
--- 368,381 ----
  }
  
  static void
! 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;
  
! 	fmgr_info_cxt(typeStruct->typinput, &arg->typfunc, arg_mcxt);
  	arg->typoid = HeapTupleGetOid(typeTup);
  	arg->typmod = -1;
  	arg->typioparam = getTypeIOParam(typeTup);
***************
*** 394,400 **** 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);
  	}
  	else if (typeStruct->typtype == TYPTYPE_COMPOSITE)
  	{
--- 392,398 ----
  	if ((funcid = get_transform_tosql(base_type, langid, trftypes)))
  	{
  		arg->func = PLyObject_ToTransform;
! 		fmgr_info_cxt(funcid, &arg->typtransform, arg_mcxt);
  	}
  	else if (typeStruct->typtype == TYPTYPE_COMPOSITE)
  	{
***************
*** 432,443 **** 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);
  	}
  }
  
  static void
! PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes)
  {
  	Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
  	Oid			element_type;
--- 430,441 ----
  		get_type_io_data(element_type, IOFunc_input,
  						 &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim,
  						 &arg->elm->typioparam, &funcid);
! 		fmgr_info_cxt(funcid, &arg->elm->typfunc, arg_mcxt);
  	}
  }
  
  static void
! 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,451 **** 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);
  	arg->typoid = HeapTupleGetOid(typeTup);
  	arg->typmod = -1;
  	arg->typioparam = getTypeIOParam(typeTup);
--- 443,449 ----
  	Oid			funcid;
  
  	/* Get the type's conversion information */
! 	fmgr_info_cxt(typeStruct->typoutput, &arg->typfunc, arg_mcxt);
  	arg->typoid = HeapTupleGetOid(typeTup);
  	arg->typmod = -1;
  	arg->typioparam = getTypeIOParam(typeTup);
***************
*** 461,467 **** 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);
  	}
  	else
  		switch (base_type)
--- 459,465 ----
  	if ((funcid = get_transform_fromsql(base_type, langid, trftypes)))
  	{
  		arg->func = PLyObject_FromTransform;
! 		fmgr_info_cxt(funcid, &arg->typtransform, arg_mcxt);
  	}
  	else
  		switch (base_type)
***************
*** 512,518 **** 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);
  	}
  }
  
--- 510,516 ----
  		get_type_io_data(element_type, IOFunc_output,
  						 &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim,
  						 &arg->elm->typioparam, &funcid);
! 		fmgr_info_cxt(funcid, &arg->elm->typfunc, arg_mcxt);
  	}
  }
  
***************
*** 758,764 **** PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
  
  	/* Create a dummy PLyTypeInfo */
  	MemSet(&info, 0, sizeof(PLyTypeInfo));
! 	PLy_typeinfo_init(&info);
  	/* Mark it as needing output routines lookup */
  	info.is_rowtype = 2;
  
--- 756,762 ----
  
  	/* Create a dummy PLyTypeInfo */
  	MemSet(&info, 0, sizeof(PLyTypeInfo));
! 	PLy_typeinfo_init(&info, CurrentMemoryContext);
  	/* Mark it as needing output routines lookup */
  	info.is_rowtype = 2;
  
***************
*** 919,925 **** 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,
  						   exec_ctx->curr_proc->langid,
  						   exec_ctx->curr_proc->trftypes);
  
--- 917,923 ----
  	if (!HeapTupleIsValid(typeTup))
  		elog(ERROR, "cache lookup failed for type %u", desc->tdtypeid);
  
! 	PLy_output_datum_func2(&info->out.d, info->mcxt, typeTup,
  						   exec_ctx->curr_proc->langid,
  						   exec_ctx->curr_proc->trftypes);
  
***************
*** 1168,1186 **** 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);
- }
--- 1166,1168 ----
*** a/src/pl/plpython/plpy_typeio.h
--- b/src/pl/plpython/plpy_typeio.h
***************
*** 88,96 **** typedef struct PLyTypeInfo
  	Oid			typ_relid;
  	TransactionId typrel_xmin;
  	ItemPointerData typrel_tid;
  } PLyTypeInfo;
  
! extern void PLy_typeinfo_init(PLyTypeInfo *arg);
  extern void PLy_typeinfo_dealloc(PLyTypeInfo *arg);
  
  extern void PLy_input_datum_func(PLyTypeInfo *arg, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes);
--- 88,98 ----
  	Oid			typ_relid;
  	TransactionId typrel_xmin;
  	ItemPointerData typrel_tid;
+ 
+ 	MemoryContext mcxt;
  } PLyTypeInfo;
  
! 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);
