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