*** 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,124 ---- return NULL; cursor->portalname = NULL; cursor->closed = false; ! ! cursor->mcxt = AllocSetContextCreate(TopMemoryContext, ! "Pl python cursor context", ! ALLOCSET_DEFAULT_MINSIZE, ! ALLOCSET_DEFAULT_INITSIZE, ! ALLOCSET_DEFAULT_MAXSIZE); ! PLy_typeinfo_init(&cursor->result, cursor->mcxt); oldcontext = CurrentMemoryContext; oldowner = CurrentResourceOwner; *************** *** 123,128 **** PLy_cursor_query(const char *query) --- 130,136 ---- PLyExecutionContext *exec_ctx = PLy_current_execution_context(); SPIPlanPtr plan; Portal portal; + MemoryContext oldcxt; pg_verifymbstr(query, strlen(query), false); *************** *** 139,145 **** PLy_cursor_query(const char *query) elog(ERROR, "SPI_cursor_open() failed: %s", SPI_result_code_string(SPI_result)); ! cursor->portalname = PLy_strdup(portal->name); PLy_spi_subtransaction_commit(oldcontext, oldowner); } --- 147,155 ---- elog(ERROR, "SPI_cursor_open() failed: %s", SPI_result_code_string(SPI_result)); ! oldcxt = MemoryContextSwitchTo(cursor->mcxt); ! cursor->portalname = pstrdup(portal->name); ! MemoryContextSwitchTo(oldcxt); PLy_spi_subtransaction_commit(oldcontext, oldowner); } *************** *** 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; --- 210,222 ---- return NULL; cursor->portalname = NULL; cursor->closed = false; ! ! cursor->mcxt = AllocSetContextCreate(TopMemoryContext, ! "Pl python cursor context", ! ALLOCSET_DEFAULT_MINSIZE, ! ALLOCSET_DEFAULT_INITSIZE, ! ALLOCSET_DEFAULT_MAXSIZE); ! PLy_typeinfo_init(&cursor->result, cursor->mcxt); oldcontext = CurrentMemoryContext; oldowner = CurrentResourceOwner; *************** *** 213,218 **** PLy_cursor_plan(PyObject *ob, PyObject *args) --- 229,235 ---- Portal portal; char *volatile nulls; volatile int j; + MemoryContext oldcxt; if (nargs > 0) nulls = palloc(nargs * sizeof(char)); *************** *** 261,267 **** PLy_cursor_plan(PyObject *ob, PyObject *args) elog(ERROR, "SPI_cursor_open() failed: %s", SPI_result_code_string(SPI_result)); ! cursor->portalname = PLy_strdup(portal->name); PLy_spi_subtransaction_commit(oldcontext, oldowner); } --- 278,286 ---- elog(ERROR, "SPI_cursor_open() failed: %s", SPI_result_code_string(SPI_result)); ! oldcxt = MemoryContextSwitchTo(cursor->mcxt); ! cursor->portalname = pstrdup(portal->name); ! MemoryContextSwitchTo(oldcxt); PLy_spi_subtransaction_commit(oldcontext, oldowner); } *************** *** 277,283 **** PLy_cursor_plan(PyObject *ob, PyObject *args) { pfree(DatumGetPointer(plan->values[k])); plan->values[k] = PointerGetDatum(NULL); ! } } Py_DECREF(cursor); --- 296,302 ---- { pfree(DatumGetPointer(plan->values[k])); plan->values[k] = PointerGetDatum(NULL); ! } } Py_DECREF(cursor); *************** *** 317,326 **** PLy_cursor_dealloc(PyObject *arg) SPI_cursor_close(portal); } ! PLy_free(cursor->portalname); cursor->portalname = NULL; PLy_typeinfo_dealloc(&cursor->result); arg->ob_type->tp_free(arg); } --- 336,346 ---- SPI_cursor_close(portal); } ! pfree(cursor->portalname); cursor->portalname = NULL; PLy_typeinfo_dealloc(&cursor->result); + MemoryContextDelete(cursor->mcxt); arg->ob_type->tp_free(arg); } *** a/src/pl/plpython/plpy_cursorobject.h --- b/src/pl/plpython/plpy_cursorobject.h *************** *** 14,19 **** typedef struct PLyCursorObject --- 14,20 ---- char *portalname; PLyTypeInfo result; bool closed; + MemoryContext mcxt; } PLyCursorObject; extern void PLy_cursor_init_type(void); *** a/src/pl/plpython/plpy_main.c --- b/src/pl/plpython/plpy_main.c *************** *** 265,270 **** plpython_inline_handler(PG_FUNCTION_ARGS) --- 265,271 ---- PLyProcedure proc; PLyExecutionContext *exec_ctx; ErrorContextCallback plerrcontext; + MemoryContext oldcxt; /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */ if (SPI_connect() != SPI_OK_CONNECT) *************** *** 277,283 **** plpython_inline_handler(PG_FUNCTION_ARGS) flinfo.fn_mcxt = CurrentMemoryContext; MemSet(&proc, 0, sizeof(PLyProcedure)); ! proc.pyname = PLy_strdup("__plpython_inline_block"); proc.langid = codeblock->langOid; proc.result.out.d.typoid = VOIDOID; --- 278,292 ---- flinfo.fn_mcxt = CurrentMemoryContext; MemSet(&proc, 0, sizeof(PLyProcedure)); ! proc.mcxt = AllocSetContextCreate(TopMemoryContext, ! "Plpy procedure context", ! ALLOCSET_DEFAULT_MINSIZE, ! ALLOCSET_DEFAULT_INITSIZE, ! ALLOCSET_DEFAULT_MAXSIZE); ! oldcxt = MemoryContextSwitchTo(proc.mcxt); ! proc.pyname = pstrdup("__plpython_inline_block"); ! MemoryContextSwitchTo(oldcxt); ! proc.langid = codeblock->langOid; proc.result.out.d.typoid = VOIDOID; *** a/src/pl/plpython/plpy_planobject.c --- b/src/pl/plpython/plpy_planobject.c *************** *** 11,17 **** #include "plpy_planobject.h" #include "plpy_elog.h" ! static void PLy_plan_dealloc(PyObject *arg); static PyObject *PLy_plan_status(PyObject *self, PyObject *args); --- 11,17 ---- #include "plpy_planobject.h" #include "plpy_elog.h" ! #include "utils/memutils.h" static void PLy_plan_dealloc(PyObject *arg); static PyObject *PLy_plan_status(PyObject *self, PyObject *args); *************** *** 80,85 **** PLy_plan_new(void) --- 80,86 ---- ob->types = NULL; ob->values = NULL; ob->args = NULL; + ob->mcxt = NULL; return (PyObject *) ob; } *************** *** 98,115 **** PLy_plan_dealloc(PyObject *arg) if (ob->plan) SPI_freeplan(ob->plan); if (ob->types) ! PLy_free(ob->types); if (ob->values) ! PLy_free(ob->values); if (ob->args) { int i; for (i = 0; i < ob->nargs; i++) PLy_typeinfo_dealloc(&ob->args[i]); ! PLy_free(ob->args); } arg->ob_type->tp_free(arg); } --- 99,118 ---- if (ob->plan) SPI_freeplan(ob->plan); if (ob->types) ! pfree(ob->types); if (ob->values) ! pfree(ob->values); if (ob->args) { int i; for (i = 0; i < ob->nargs; i++) PLy_typeinfo_dealloc(&ob->args[i]); ! pfree(ob->args); } + if (ob->mcxt) + MemoryContextDelete(ob->mcxt); arg->ob_type->tp_free(arg); } *** a/src/pl/plpython/plpy_planobject.h --- b/src/pl/plpython/plpy_planobject.h *************** *** 17,22 **** typedef struct PLyPlanObject --- 17,23 ---- Oid *types; Datum *values; PLyTypeInfo *args; + MemoryContext mcxt; } PLyPlanObject; extern void PLy_plan_init_type(void); *** a/src/pl/plpython/plpy_procedure.c --- b/src/pl/plpython/plpy_procedure.c *************** *** 113,119 **** PLy_procedure_get(Oid fn_oid, Oid fn_rel, bool is_trigger) { /* Found it, but it's invalid, free and reuse the cache entry */ PLy_procedure_delete(proc); - PLy_free(proc); proc = PLy_procedure_create(procTup, fn_oid, is_trigger); entry->proc = proc; } --- 113,118 ---- *************** *** 145,150 **** PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) --- 144,151 ---- char *volatile procSource = NULL; Datum prosrcdatum; bool isnull; + MemoryContext cxt; + MemoryContext oldcxt; int i, rv; *************** *** 156,183 **** PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) if (rv >= sizeof(procName) || rv < 0) elog(ERROR, "procedure name would overrun buffer"); ! proc = PLy_malloc(sizeof(PLyProcedure)); ! proc->proname = PLy_strdup(NameStr(procStruct->proname)); ! proc->pyname = PLy_strdup(procName); proc->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data); proc->fn_tid = procTup->t_self; /* 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; { - MemoryContext oldcxt; - Datum protrftypes_datum = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_protrftypes, &isnull); - oldcxt = MemoryContextSwitchTo(TopMemoryContext); proc->trftypes = isnull ? NIL : oid_array_to_list(protrftypes_datum); - MemoryContextSwitchTo(oldcxt); } proc->code = proc->statics = NULL; proc->globals = NULL; --- 157,190 ---- if (rv >= sizeof(procName) || rv < 0) elog(ERROR, "procedure name would overrun buffer"); ! cxt = AllocSetContextCreate(TopMemoryContext, ! "Plpy procedure context", ! ALLOCSET_DEFAULT_MINSIZE, ! ALLOCSET_DEFAULT_INITSIZE, ! ALLOCSET_DEFAULT_MAXSIZE); ! ! oldcxt = MemoryContextSwitchTo(cxt); ! ! proc = palloc(sizeof(PLyProcedure)); ! proc->mcxt = cxt; ! ! proc->proname = pstrdup(NameStr(procStruct->proname)); ! proc->pyname = pstrdup(procName); proc->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data); proc->fn_tid = procTup->t_self; /* Remember if function is STABLE/IMMUTABLE */ proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE); ! 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; { Datum protrftypes_datum = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_protrftypes, &isnull); proc->trftypes = isnull ? NIL : oid_array_to_list(protrftypes_datum); } proc->code = proc->statics = NULL; proc->globals = NULL; *************** *** 271,277 **** PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) } } ! proc->argnames = (char **) PLy_malloc0(sizeof(char *) * proc->nargs); for (i = pos = 0; i < total; i++) { HeapTuple argTypeTup; --- 278,284 ---- } } ! proc->argnames = (char **) palloc0(sizeof(char *) * proc->nargs); for (i = pos = 0; i < total; i++) { HeapTuple argTypeTup; *************** *** 314,320 **** PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) } /* get argument name */ ! proc->argnames[pos] = names ? PLy_strdup(names[i]) : NULL; ReleaseSysCache(argTypeTup); --- 321,327 ---- } /* get argument name */ ! proc->argnames[pos] = names ? pstrdup(names[i]) : NULL; ReleaseSysCache(argTypeTup); *************** *** 346,351 **** PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) --- 353,359 ---- } PG_END_TRY(); + MemoryContextSwitchTo(oldcxt); return proc; } *************** *** 357,362 **** PLy_procedure_compile(PLyProcedure *proc, const char *src) --- 365,371 ---- { PyObject *crv = NULL; char *msrc; + MemoryContext oldcxt; proc->globals = PyDict_Copy(PLy_interp_globals); *************** *** 372,378 **** PLy_procedure_compile(PLyProcedure *proc, const char *src) */ msrc = PLy_procedure_munge_source(proc->pyname, src); /* Save the mangled source for later inclusion in tracebacks */ ! proc->src = PLy_strdup(msrc); crv = PyRun_String(msrc, Py_file_input, proc->globals, NULL); pfree(msrc); --- 381,390 ---- */ msrc = PLy_procedure_munge_source(proc->pyname, src); /* Save the mangled source for later inclusion in tracebacks */ ! oldcxt = MemoryContextSwitchTo(proc->mcxt); ! proc->src = pstrdup(msrc); ! MemoryContextSwitchTo(oldcxt); ! crv = PyRun_String(msrc, Py_file_input, proc->globals, NULL); pfree(msrc); *************** *** 410,434 **** PLy_procedure_delete(PLyProcedure *proc) Py_XDECREF(proc->statics); Py_XDECREF(proc->globals); if (proc->proname) ! PLy_free(proc->proname); if (proc->pyname) ! PLy_free(proc->pyname); for (i = 0; i < proc->nargs; i++) { if (proc->args[i].is_rowtype == 1) { if (proc->args[i].in.r.atts) ! PLy_free(proc->args[i].in.r.atts); if (proc->args[i].out.r.atts) ! PLy_free(proc->args[i].out.r.atts); } if (proc->argnames && proc->argnames[i]) ! PLy_free(proc->argnames[i]); } if (proc->src) ! PLy_free(proc->src); if (proc->argnames) ! PLy_free(proc->argnames); } /* --- 422,448 ---- Py_XDECREF(proc->statics); Py_XDECREF(proc->globals); if (proc->proname) ! pfree(proc->proname); if (proc->pyname) ! pfree(proc->pyname); for (i = 0; i < proc->nargs; i++) { if (proc->args[i].is_rowtype == 1) { if (proc->args[i].in.r.atts) ! pfree(proc->args[i].in.r.atts); if (proc->args[i].out.r.atts) ! pfree(proc->args[i].out.r.atts); } if (proc->argnames && proc->argnames[i]) ! pfree(proc->argnames[i]); } if (proc->src) ! pfree(proc->src); if (proc->argnames) ! pfree(proc->argnames); ! ! MemoryContextDelete(proc->mcxt); } /* *** a/src/pl/plpython/plpy_procedure.h --- b/src/pl/plpython/plpy_procedure.h *************** *** 32,37 **** typedef struct PLyProcedure --- 32,39 ---- PyObject *code; /* compiled procedure code */ PyObject *statics; /* data saved across calls, local scope */ PyObject *globals; /* data saved across calls, global scope */ + MemoryContext mcxt; /* Context to store the plyprocedure and it's input + * or output data. */ } PLyProcedure; /* the procedure cache key */ *** a/src/pl/plpython/plpy_spi.c --- b/src/pl/plpython/plpy_spi.c *************** *** 60,72 **** PLy_spi_prepare(PyObject *self, PyObject *args) if ((plan = (PLyPlanObject *) PLy_plan_new()) == NULL) return NULL; nargs = list ? PySequence_Length(list) : 0; plan->nargs = nargs; ! plan->types = nargs ? PLy_malloc(sizeof(Oid) * nargs) : NULL; ! plan->values = nargs ? PLy_malloc(sizeof(Datum) * nargs) : NULL; ! plan->args = nargs ? PLy_malloc(sizeof(PLyTypeInfo) * nargs) : NULL; oldcontext = CurrentMemoryContext; oldowner = CurrentResourceOwner; --- 60,81 ---- if ((plan = (PLyPlanObject *) PLy_plan_new()) == NULL) return NULL; + + plan->mcxt = AllocSetContextCreate(TopMemoryContext, + "PL python plan context", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + oldcontext = MemoryContextSwitchTo(plan->mcxt); nargs = list ? PySequence_Length(list) : 0; plan->nargs = nargs; ! plan->types = nargs ? palloc(sizeof(Oid) * nargs) : NULL; ! plan->values = nargs ? palloc(sizeof(Datum) * nargs) : NULL; ! plan->args = nargs ? palloc(sizeof(PLyTypeInfo) * nargs) : NULL; ! ! MemoryContextSwitchTo(oldcontext); oldcontext = CurrentMemoryContext; oldowner = CurrentResourceOwner; *************** *** 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); } --- 93,99 ---- */ for (i = 0; i < nargs; i++) { ! PLy_typeinfo_init(&plan->args[i], plan->mcxt); plan->values[i] = PointerGetDatum(NULL); } *************** *** 391,400 **** PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status) { PLyTypeInfo args; int i; Py_DECREF(result->nrows); result->nrows = PyInt_FromLong(rows); ! PLy_typeinfo_init(&args); oldcontext = CurrentMemoryContext; PG_TRY(); --- 400,416 ---- { PLyTypeInfo args; int i; + MemoryContext cxt; Py_DECREF(result->nrows); result->nrows = PyInt_FromLong(rows); ! ! cxt = AllocSetContextCreate(CurrentMemoryContext, ! "Pl python temp context", ! ALLOCSET_DEFAULT_MINSIZE, ! ALLOCSET_DEFAULT_INITSIZE, ! ALLOCSET_DEFAULT_MAXSIZE); ! PLy_typeinfo_init(&args, cxt); oldcontext = CurrentMemoryContext; PG_TRY(); *************** *** 433,444 **** PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status) --- 449,462 ---- { MemoryContextSwitchTo(oldcontext); PLy_typeinfo_dealloc(&args); + MemoryContextDelete(cxt); Py_DECREF(result); PG_RE_THROW(); } PG_END_TRY(); PLy_typeinfo_dealloc(&args); + MemoryContextDelete(cxt); SPI_freetuptable(tuptable); } *** 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 *************** *** 85,101 **** PLy_typeinfo_dealloc(PLyTypeInfo *arg) for (i = 0; i < arg->in.r.natts; i++) { if (arg->in.r.atts[i].elm != NULL) ! PLy_free(arg->in.r.atts[i].elm); } if (arg->in.r.atts) ! PLy_free(arg->in.r.atts); for (i = 0; i < arg->out.r.natts; i++) { if (arg->out.r.atts[i].elm != NULL) ! PLy_free(arg->out.r.atts[i].elm); } if (arg->out.r.atts) ! PLy_free(arg->out.r.atts); } } --- 83,99 ---- for (i = 0; i < arg->in.r.natts; i++) { if (arg->in.r.atts[i].elm != NULL) ! pfree(arg->in.r.atts[i].elm); } if (arg->in.r.atts) ! pfree(arg->in.r.atts); for (i = 0; i < arg->out.r.natts; i++) { if (arg->out.r.atts[i].elm != NULL) ! pfree(arg->out.r.atts[i].elm); } if (arg->out.r.atts) ! pfree(arg->out.r.atts); } } *************** *** 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 *************** *** 126,131 **** PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc) --- 124,132 ---- { int i; PLyExecutionContext *exec_ctx = PLy_current_execution_context(); + MemoryContext oldcxt; + + oldcxt = MemoryContextSwitchTo(arg->mcxt); if (arg->is_rowtype == 0) elog(ERROR, "PLyTypeInfo struct is initialized for a Datum"); *************** *** 134,142 **** PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc) if (arg->in.r.natts != desc->natts) { if (arg->in.r.atts) ! PLy_free(arg->in.r.atts); arg->in.r.natts = desc->natts; ! arg->in.r.atts = PLy_malloc0(desc->natts * sizeof(PLyDatumToOb)); } /* Can this be an unnamed tuple? If not, then an Assert would be enough */ --- 135,143 ---- if (arg->in.r.natts != desc->natts) { if (arg->in.r.atts) ! pfree(arg->in.r.atts); arg->in.r.natts = desc->natts; ! arg->in.r.atts = palloc0(desc->natts * sizeof(PLyDatumToOb)); } /* Can this be an unnamed tuple? If not, then an Assert would be enough */ *************** *** 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, --- 183,189 ---- 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, *************** *** 190,195 **** PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc) --- 191,198 ---- ReleaseSysCache(typeTup); } + + MemoryContextSwitchTo(oldcxt); } void *************** *** 197,202 **** PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc) --- 200,208 ---- { int i; PLyExecutionContext *exec_ctx = PLy_current_execution_context(); + MemoryContext oldcxt; + + oldcxt = MemoryContextSwitchTo(arg->mcxt); if (arg->is_rowtype == 0) elog(ERROR, "PLyTypeInfo struct is initialized for a Datum"); *************** *** 205,213 **** PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc) if (arg->out.r.natts != desc->natts) { if (arg->out.r.atts) ! PLy_free(arg->out.r.atts); arg->out.r.natts = desc->natts; ! arg->out.r.atts = PLy_malloc0(desc->natts * sizeof(PLyObToDatum)); } Assert(OidIsValid(desc->tdtypeid)); --- 211,219 ---- if (arg->out.r.natts != desc->natts) { if (arg->out.r.atts) ! pfree(arg->out.r.atts); arg->out.r.natts = desc->natts; ! arg->out.r.atts = palloc0(desc->natts * sizeof(PLyObToDatum)); } Assert(OidIsValid(desc->tdtypeid)); *************** *** 249,260 **** 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); ReleaseSysCache(typeTup); } } void --- 255,268 ---- 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); ReleaseSysCache(typeTup); } + + MemoryContextSwitchTo(oldcxt); } void *************** *** 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); --- 378,394 ---- } 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; + MemoryContext oldcxt; + + oldcxt = MemoryContextSwitchTo(arg_mcxt); ! 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) { --- 405,411 ---- 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) { *************** *** 422,428 **** PLy_output_datum_func2(PLyObToDatum *arg, HeapTuple typeTup, Oid langid, List *t if (type_is_rowtype(element_type)) arg->func = PLyObject_ToComposite; ! arg->elm = PLy_malloc0(sizeof(*arg->elm)); arg->elm->func = arg->func; arg->elm->typtransform = arg->typtransform; arg->func = PLySequence_ToArray; --- 433,439 ---- if (type_is_rowtype(element_type)) arg->func = PLyObject_ToComposite; ! arg->elm = palloc0(sizeof(*arg->elm)); arg->elm->func = arg->func; arg->elm->typtransform = arg->typtransform; arg->func = PLySequence_ToArray; *************** *** 432,451 **** 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; Oid base_type; 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,467 ---- 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); } + + MemoryContextSwitchTo(oldcxt); } 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; Oid base_type; Oid funcid; + MemoryContext oldcxt; + + oldcxt = MemoryContextSwitchTo(arg_mcxt); /* 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) --- 477,483 ---- 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) *************** *** 503,509 **** PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup, Oid lan char dummy_delim; Oid funcid; ! arg->elm = PLy_malloc0(sizeof(*arg->elm)); arg->elm->func = arg->func; arg->elm->typtransform = arg->typtransform; arg->func = PLyList_FromArray; --- 519,525 ---- char dummy_delim; Oid funcid; ! arg->elm = palloc0(sizeof(*arg->elm)); arg->elm->func = arg->func; arg->elm->typtransform = arg->typtransform; arg->func = PLyList_FromArray; *************** *** 512,519 **** 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); } } static PyObject * --- 528,537 ---- 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); } + + MemoryContextSwitchTo(oldcxt); } static PyObject * *************** *** 752,764 **** PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv) Datum rv; PLyTypeInfo info; TupleDesc desc; if (typmod != -1) elog(ERROR, "received unnamed record type as input"); /* Create a dummy PLyTypeInfo */ MemSet(&info, 0, sizeof(PLyTypeInfo)); ! PLy_typeinfo_init(&info); /* Mark it as needing output routines lookup */ info.is_rowtype = 2; --- 770,789 ---- Datum rv; PLyTypeInfo info; TupleDesc desc; + MemoryContext cxt; if (typmod != -1) elog(ERROR, "received unnamed record type as input"); + cxt = AllocSetContextCreate(CurrentMemoryContext, + "PL python temp context", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + /* Create a dummy PLyTypeInfo */ MemSet(&info, 0, sizeof(PLyTypeInfo)); ! PLy_typeinfo_init(&info, cxt); /* Mark it as needing output routines lookup */ info.is_rowtype = 2; *************** *** 775,780 **** PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv) --- 800,806 ---- ReleaseTupleDesc(desc); PLy_typeinfo_dealloc(&info); + MemoryContextDelete(cxt); return rv; } *************** *** 916,931 **** PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string) HeapTuple typeTup; PLyTypeInfo locinfo; PLyExecutionContext *exec_ctx = PLy_current_execution_context(); /* Create a dummy PLyTypeInfo */ MemSet(&locinfo, 0, sizeof(PLyTypeInfo)); ! PLy_typeinfo_init(&locinfo); typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(desc->tdtypeid)); if (!HeapTupleIsValid(typeTup)) elog(ERROR, "cache lookup failed for type %u", desc->tdtypeid); ! PLy_output_datum_func2(&locinfo.out.d, typeTup, exec_ctx->curr_proc->langid, exec_ctx->curr_proc->trftypes); --- 942,964 ---- HeapTuple typeTup; PLyTypeInfo locinfo; PLyExecutionContext *exec_ctx = PLy_current_execution_context(); + MemoryContext cxt; + + cxt = AllocSetContextCreate(CurrentMemoryContext, + "PL python temp context", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); /* Create a dummy PLyTypeInfo */ MemSet(&locinfo, 0, sizeof(PLyTypeInfo)); ! PLy_typeinfo_init(&locinfo, cxt); typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(desc->tdtypeid)); if (!HeapTupleIsValid(typeTup)) elog(ERROR, "cache lookup failed for type %u", desc->tdtypeid); ! PLy_output_datum_func2(&locinfo.out.d, locinfo.mcxt, typeTup, exec_ctx->curr_proc->langid, exec_ctx->curr_proc->trftypes); *************** *** 934,939 **** PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string) --- 967,973 ---- result = PLyObject_ToDatum(&locinfo.out.d, desc->tdtypmod, string); PLy_typeinfo_dealloc(&locinfo); + MemoryContextDelete(cxt); return result; } *************** *** 1178,1196 **** 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); - } --- 1212,1214 ---- *** 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); *** a/src/pl/plpython/plpy_util.c --- b/src/pl/plpython/plpy_util.c *************** *** 24,51 **** PLy_malloc(size_t bytes) return MemoryContextAlloc(TopMemoryContext, bytes); } - void * - PLy_malloc0(size_t bytes) - { - void *ptr = PLy_malloc(bytes); - - MemSet(ptr, 0, bytes); - return ptr; - } - - char * - PLy_strdup(const char *str) - { - char *result; - size_t len; - - len = strlen(str) + 1; - result = PLy_malloc(len); - memcpy(result, str, len); - - return result; - } - /* define this away */ void PLy_free(void *ptr) --- 24,29 ---- *** a/src/pl/plpython/plpy_util.h --- b/src/pl/plpython/plpy_util.h *************** *** 7,14 **** #define PLPY_UTIL_H extern void *PLy_malloc(size_t bytes); - extern void *PLy_malloc0(size_t bytes); - extern char *PLy_strdup(const char *str); extern void PLy_free(void *ptr); extern PyObject *PLyUnicode_Bytes(PyObject *unicode); --- 7,12 ----