diff --git a/src/pl/plpython/plpy_cursorobject.c b/src/pl/plpython/plpy_cursorobject.c index 2c458d35fdb1a19fad1a46670487d6468f63384b..103571ba15cc0befd1fea5fede49f0dfc67c4b82 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,12 @@ PLy_cursor_query(const char *query) return NULL; cursor->portalname = NULL; cursor->closed = false; - PLy_typeinfo_init(&cursor->result); + 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; @@ -139,7 +145,7 @@ 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); + cursor->portalname = MemoryContextStrdup(cursor->mcxt, portal->name); PLy_spi_subtransaction_commit(oldcontext, oldowner); } @@ -200,7 +206,12 @@ PLy_cursor_plan(PyObject *ob, PyObject *args) return NULL; cursor->portalname = NULL; cursor->closed = false; - PLy_typeinfo_init(&cursor->result); + 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; @@ -261,7 +272,7 @@ 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); + cursor->portalname = MemoryContextStrdup(cursor->mcxt, portal->name); PLy_spi_subtransaction_commit(oldcontext, oldowner); } @@ -315,12 +326,13 @@ PLy_cursor_dealloc(PyObject *arg) if (PortalIsValid(portal)) SPI_cursor_close(portal); + cursor->closed = true; + } + if (cursor->mcxt) + { + MemoryContextDelete(cursor->mcxt); + cursor->mcxt = NULL; } - - PLy_free(cursor->portalname); - cursor->portalname = NULL; - - PLy_typeinfo_dealloc(&cursor->result); arg->ob_type->tp_free(arg); } diff --git a/src/pl/plpython/plpy_cursorobject.h b/src/pl/plpython/plpy_cursorobject.h index 3c28f4f8e716eb2f97704447ae62ff20ea789f69..c73033c486bbe60a314f7935ce6ddb234f830144 100644 --- a/src/pl/plpython/plpy_cursorobject.h +++ b/src/pl/plpython/plpy_cursorobject.h @@ -14,6 +14,7 @@ typedef struct PLyCursorObject char *portalname; PLyTypeInfo result; bool closed; + MemoryContext mcxt; } PLyCursorObject; extern void PLy_cursor_init_type(void); diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c index 3ccebe403e428ad5281e3f3a11b73272fc21978f..24aed011e4b65819f05f144f7e49c0cca237b693 100644 --- a/src/pl/plpython/plpy_exec.c +++ b/src/pl/plpython/plpy_exec.c @@ -852,6 +852,6 @@ PLy_abort_open_subtransactions(int save_subxact_level) MemoryContextSwitchTo(subtransactiondata->oldcontext); CurrentResourceOwner = subtransactiondata->oldowner; - PLy_free(subtransactiondata); + pfree(subtransactiondata); } } diff --git a/src/pl/plpython/plpy_main.c b/src/pl/plpython/plpy_main.c index 63a284e238411ca8aaf1e83bb1061aa24f853210..3c2ebfa16afb55094cfc8897326e22190dd38b73 100644 --- a/src/pl/plpython/plpy_main.c +++ b/src/pl/plpython/plpy_main.c @@ -277,7 +277,12 @@ plpython_inline_handler(PG_FUNCTION_ARGS) flinfo.fn_mcxt = CurrentMemoryContext; MemSet(&proc, 0, sizeof(PLyProcedure)); - proc.pyname = PLy_strdup("__plpython_inline_block"); + proc.mcxt = AllocSetContextCreate(TopMemoryContext, + "__plpython_inline_block", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + proc.pyname = MemoryContextStrdup(proc.mcxt, "__plpython_inline_block"); proc.langid = codeblock->langOid; proc.result.out.d.typoid = VOIDOID; @@ -364,17 +369,32 @@ PLy_current_execution_context(void) return PLy_execution_contexts; } +MemoryContext +PLy_get_scratch_context(PLyExecutionContext *context) +{ + /* + * A scratch context might never be needed in a given plpython procedure, + * so allocate it on first request. + */ + if (context->scratch_ctx == NULL) + context->scratch_ctx = + AllocSetContextCreate(TopTransactionContext, + "PL/Python scratch context", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + return context->scratch_ctx; +} + static PLyExecutionContext * PLy_push_execution_context(void) { - PLyExecutionContext *context = PLy_malloc(sizeof(PLyExecutionContext)); + PLyExecutionContext *context; + context = (PLyExecutionContext *) + MemoryContextAlloc(TopTransactionContext, sizeof(PLyExecutionContext)); context->curr_proc = NULL; - context->scratch_ctx = AllocSetContextCreate(TopTransactionContext, - "PL/Python scratch context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + context->scratch_ctx = NULL; context->next = PLy_execution_contexts; PLy_execution_contexts = context; return context; @@ -390,6 +410,7 @@ PLy_pop_execution_context(void) PLy_execution_contexts = context->next; - MemoryContextDelete(context->scratch_ctx); - PLy_free(context); + if (context->scratch_ctx) + MemoryContextDelete(context->scratch_ctx); + pfree(context); } diff --git a/src/pl/plpython/plpy_main.h b/src/pl/plpython/plpy_main.h index b13e2c21a111b045f61fdc4da23ba583003e0ed4..10426c43236b9c52274b9280352039446cd20cce 100644 --- a/src/pl/plpython/plpy_main.h +++ b/src/pl/plpython/plpy_main.h @@ -25,4 +25,7 @@ typedef struct PLyExecutionContext /* Get the current execution context */ extern PLyExecutionContext *PLy_current_execution_context(void); +/* Get the scratch memory context for specified execution context */ +extern MemoryContext PLy_get_scratch_context(PLyExecutionContext *context); + #endif /* PLPY_MAIN_H */ diff --git a/src/pl/plpython/plpy_planobject.c b/src/pl/plpython/plpy_planobject.c index 8305bd68e96cc640a4725d53f8798302314a3439..a9040efb502b2a09951a5ce5751a15a05feb463c 100644 --- a/src/pl/plpython/plpy_planobject.c +++ b/src/pl/plpython/plpy_planobject.c @@ -11,6 +11,7 @@ #include "plpy_planobject.h" #include "plpy_elog.h" +#include "utils/memutils.h" static void PLy_plan_dealloc(PyObject *arg); @@ -80,6 +81,7 @@ PLy_plan_new(void) ob->types = NULL; ob->values = NULL; ob->args = NULL; + ob->mcxt = NULL; return (PyObject *) ob; } @@ -96,20 +98,15 @@ PLy_plan_dealloc(PyObject *arg) PLyPlanObject *ob = (PLyPlanObject *) 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) + ob->plan = NULL; + } + if (ob->mcxt) { - int i; - - for (i = 0; i < ob->nargs; i++) - PLy_typeinfo_dealloc(&ob->args[i]); - PLy_free(ob->args); + MemoryContextDelete(ob->mcxt); + ob->mcxt = NULL; } - arg->ob_type->tp_free(arg); } diff --git a/src/pl/plpython/plpy_planobject.h b/src/pl/plpython/plpy_planobject.h index 7a89ffc2c18090355b500434545b7555c92ccec2..c67559266ec5a71b99532197399b27205591a61b 100644 --- a/src/pl/plpython/plpy_planobject.h +++ b/src/pl/plpython/plpy_planobject.h @@ -17,6 +17,7 @@ typedef struct PLyPlanObject Oid *types; Datum *values; PLyTypeInfo *args; + MemoryContext mcxt; } PLyPlanObject; extern void PLy_plan_init_type(void); diff --git a/src/pl/plpython/plpy_procedure.c b/src/pl/plpython/plpy_procedure.c index 16ff84560bbf402e05c1ae41d49bcb66e470027f..e1f56209ef00568feea49d1dc3db5cf3f26d166f 100644 --- a/src/pl/plpython/plpy_procedure.c +++ b/src/pl/plpython/plpy_procedure.c @@ -112,8 +112,9 @@ PLy_procedure_get(Oid fn_oid, Oid fn_rel, bool is_trigger) else if (!PLy_procedure_valid(proc, procTup)) { /* Found it, but it's invalid, free and reuse the cache entry */ - PLy_procedure_delete(proc); - PLy_free(proc); + entry->proc = NULL; + if (proc) + PLy_procedure_delete(proc); proc = PLy_procedure_create(procTup, fn_oid, is_trigger); entry->proc = proc; } @@ -142,11 +143,9 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) char procName[NAMEDATALEN + 256]; Form_pg_proc procStruct; PLyProcedure *volatile proc; - char *volatile procSource = NULL; - Datum prosrcdatum; - bool isnull; - int i, - rv; + MemoryContext cxt; + MemoryContext oldcxt; + int rv; procStruct = (Form_pg_proc) GETSTRUCT(procTup); rv = snprintf(procName, sizeof(procName), @@ -156,38 +155,48 @@ 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; + cxt = AllocSetContextCreate(TopMemoryContext, + procName, + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); - Datum protrftypes_datum = SysCacheGetAttr(PROCOID, procTup, - Anum_pg_proc_protrftypes, &isnull); + oldcxt = MemoryContextSwitchTo(cxt); - oldcxt = MemoryContextSwitchTo(TopMemoryContext); - proc->trftypes = isnull ? NIL : oid_array_to_list(protrftypes_datum); - MemoryContextSwitchTo(oldcxt); - } - proc->code = proc->statics = NULL; - proc->globals = NULL; - proc->is_setof = procStruct->proretset; - proc->setof = NULL; - proc->src = NULL; - proc->argnames = NULL; + proc = (PLyProcedure *) palloc0(sizeof(PLyProcedure)); + proc->mcxt = cxt; PG_TRY(); { + Datum protrftypes_datum; + Datum prosrcdatum; + bool isnull; + char *procSource; + int i; + + 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; + 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; + proc->is_setof = procStruct->proretset; + proc->setof = NULL; + proc->src = NULL; + proc->argnames = NULL; + /* * get information required for output conversion of the return value, * but only if this isn't a trigger. @@ -250,8 +259,7 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) Oid *types; char **names, *modes; - int i, - pos, + int pos, total; /* extract argument type info from the pg_proc tuple */ @@ -271,7 +279,7 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) } } - proc->argnames = (char **) PLy_malloc0(sizeof(char *) * proc->nargs); + proc->argnames = (char **) palloc0(sizeof(char *) * proc->nargs); for (i = pos = 0; i < total; i++) { HeapTuple argTypeTup; @@ -314,7 +322,7 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) } /* get argument name */ - proc->argnames[pos] = names ? PLy_strdup(names[i]) : NULL; + proc->argnames[pos] = names ? pstrdup(names[i]) : NULL; ReleaseSysCache(argTypeTup); @@ -334,18 +342,16 @@ PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is_trigger) PLy_procedure_compile(proc, procSource); pfree(procSource); - procSource = NULL; } PG_CATCH(); { + MemoryContextSwitchTo(oldcxt); PLy_procedure_delete(proc); - if (procSource) - pfree(procSource); - PG_RE_THROW(); } PG_END_TRY(); + MemoryContextSwitchTo(oldcxt); return proc; } @@ -372,7 +378,7 @@ 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); + proc->src = MemoryContextStrdup(proc->mcxt, msrc); crv = PyRun_String(msrc, Py_file_input, proc->globals, NULL); pfree(msrc); @@ -404,31 +410,10 @@ PLy_procedure_compile(PLyProcedure *proc, const char *src) void PLy_procedure_delete(PLyProcedure *proc) { - int i; - Py_XDECREF(proc->code); 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); + MemoryContextDelete(proc->mcxt); } /* @@ -479,7 +464,8 @@ PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup) int i; bool valid; - Assert(proc != NULL); + if (proc == NULL) + return false; /* If the pg_proc tuple has changed, it's not valid */ if (!(proc->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) && diff --git a/src/pl/plpython/plpy_procedure.h b/src/pl/plpython/plpy_procedure.h index 6d4b00ba7c88a795c1136c396390e6aa540001a6..9fc8db079724a10980a9fcdcdd5d7e32b95d93c2 100644 --- a/src/pl/plpython/plpy_procedure.h +++ b/src/pl/plpython/plpy_procedure.h @@ -14,6 +14,8 @@ extern void init_procedure_caches(void); /* cached procedure data */ typedef struct PLyProcedure { + MemoryContext mcxt; /* context holding this PLyProcedure and its + * subsidiary data */ char *proname; /* SQL name of procedure */ char *pyname; /* Python name of procedure */ TransactionId fn_xmin; diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c index d0e255f8359d3d7c8f119470dc8ff6edd045b5fd..58e78ecebcb39139ee677727cf1b6807722ed03d 100644 --- a/src/pl/plpython/plpy_spi.c +++ b/src/pl/plpython/plpy_spi.c @@ -61,12 +61,21 @@ PLy_spi_prepare(PyObject *self, PyObject *args) 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 ? PLy_malloc(sizeof(Oid) * nargs) : NULL; - plan->values = nargs ? PLy_malloc(sizeof(Datum) * nargs) : NULL; - plan->args = nargs ? PLy_malloc(sizeof(PLyTypeInfo) * nargs) : NULL; + 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,7 +93,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], plan->mcxt); plan->values[i] = PointerGetDatum(NULL); } @@ -391,10 +400,17 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status) { PLyTypeInfo args; int i; + MemoryContext cxt; Py_DECREF(result->nrows); result->nrows = PyInt_FromLong(rows); - PLy_typeinfo_init(&args); + + 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(); @@ -432,13 +448,13 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status) PG_CATCH(); { 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); } diff --git a/src/pl/plpython/plpy_subxactobject.c b/src/pl/plpython/plpy_subxactobject.c index 2e7ec4fdab49945c3e2edc5e2cb8c934c4dab1df..81fb3a3a4ab8761a2f79a467223afa8dcfd5aad0 100644 --- a/src/pl/plpython/plpy_subxactobject.c +++ b/src/pl/plpython/plpy_subxactobject.c @@ -8,6 +8,7 @@ #include "access/xact.h" #include "executor/spi.h" +#include "utils/memutils.h" #include "plpython.h" @@ -132,16 +133,22 @@ PLy_subtransaction_enter(PyObject *self, PyObject *unused) subxact->started = true; oldcontext = CurrentMemoryContext; - subxactdata = PLy_malloc(sizeof(*subxactdata)); + subxactdata = (PLySubtransactionData *) + MemoryContextAlloc(TopTransactionContext, + sizeof(PLySubtransactionData)); + subxactdata->oldcontext = oldcontext; subxactdata->oldowner = CurrentResourceOwner; BeginInternalSubTransaction(NULL); - /* Do not want to leave the previous memory context */ - MemoryContextSwitchTo(oldcontext); + /* Be sure that cells of explicit_subtransactions list are long-lived */ + MemoryContextSwitchTo(TopTransactionContext); explicit_subtransactions = lcons(subxactdata, explicit_subtransactions); + /* Caller wants to stay in original memory context */ + MemoryContextSwitchTo(oldcontext); + Py_INCREF(self); return self; } @@ -204,7 +211,7 @@ PLy_subtransaction_exit(PyObject *self, PyObject *args) MemoryContextSwitchTo(subxactdata->oldcontext); CurrentResourceOwner = subxactdata->oldowner; - PLy_free(subxactdata); + pfree(subxactdata); /* * AtEOSubXact_SPI() should not have popped any SPI context, but just in diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c index 05add6e2ce88f8a402bde968ea4bcc36e2ddc975..7ad7a4400a53fdbc4eab28a1c99720fe4608ea1c 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,30 +70,7 @@ PLy_typeinfo_init(PLyTypeInfo *arg) arg->typ_relid = InvalidOid; arg->typrel_xmin = InvalidTransactionId; ItemPointerSetInvalid(&arg->typrel_tid); -} - -void -PLy_typeinfo_dealloc(PLyTypeInfo *arg) -{ - if (arg->is_rowtype == 1) - { - int i; - - 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); - } + arg->mcxt = mcxt; } /* @@ -109,7 +83,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 +92,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 @@ -126,6 +100,9 @@ PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc) { 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,9 +111,9 @@ 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); + pfree(arg->in.r.atts); arg->in.r.natts = desc->natts; - arg->in.r.atts = PLy_malloc0(desc->natts * sizeof(PLyDatumToOb)); + arg->in.r.atts = palloc0(desc->natts * sizeof(PLyDatumToOb)); } /* Can this be an unnamed tuple? If not, then an Assert would be enough */ @@ -182,7 +159,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, @@ -190,6 +167,8 @@ PLy_input_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc) ReleaseSysCache(typeTup); } + + MemoryContextSwitchTo(oldcxt); } void @@ -197,6 +176,9 @@ PLy_output_tuple_funcs(PLyTypeInfo *arg, TupleDesc desc) { 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,9 +187,9 @@ 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); + pfree(arg->out.r.atts); arg->out.r.natts = desc->natts; - arg->out.r.atts = PLy_malloc0(desc->natts * sizeof(PLyObToDatum)); + arg->out.r.atts = palloc0(desc->natts * sizeof(PLyObToDatum)); } Assert(OidIsValid(desc->tdtypeid)); @@ -249,12 +231,14 @@ 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); ReleaseSysCache(typeTup); } + + MemoryContextSwitchTo(oldcxt); } void @@ -291,8 +275,8 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc) { PyObject *volatile dict; PLyExecutionContext *exec_ctx = PLy_current_execution_context(); + MemoryContext scratch_context = PLy_get_scratch_context(exec_ctx); MemoryContext oldcontext = CurrentMemoryContext; - int i; if (info->is_rowtype != 1) elog(ERROR, "PLyTypeInfo structure describes a datum"); @@ -303,11 +287,13 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc) PG_TRY(); { + int i; + /* * Do the work in the scratch context to avoid leaking memory from the * datatype output function calls. */ - MemoryContextSwitchTo(exec_ctx->scratch_ctx); + MemoryContextSwitchTo(scratch_context); for (i = 0; i < info->in.r.natts; i++) { char *key; @@ -331,7 +317,7 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc) } } MemoryContextSwitchTo(oldcontext); - MemoryContextReset(exec_ctx->scratch_ctx); + MemoryContextReset(scratch_context); } PG_CATCH(); { @@ -370,14 +356,17 @@ 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; + MemoryContext oldcxt; - perm_fmgr_info(typeStruct->typinput, &arg->typfunc); + 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,7 +383,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) { @@ -422,7 +411,7 @@ 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 = palloc0(sizeof(*arg->elm)); arg->elm->func = arg->func; arg->elm->typtransform = arg->typtransform; arg->func = PLySequence_ToArray; @@ -432,20 +421,25 @@ 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); } + + MemoryContextSwitchTo(oldcxt); } 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; Oid base_type; Oid funcid; + MemoryContext oldcxt; + + oldcxt = MemoryContextSwitchTo(arg_mcxt); /* 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 +455,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) @@ -503,7 +497,7 @@ 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 = palloc0(sizeof(*arg->elm)); arg->elm->func = arg->func; arg->elm->typtransform = arg->typtransform; arg->func = PLyList_FromArray; @@ -512,8 +506,10 @@ 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); } + + MemoryContextSwitchTo(oldcxt); } static PyObject * @@ -752,13 +748,19 @@ PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv) Datum rv; PLyTypeInfo info; TupleDesc desc; + MemoryContext cxt; if (typmod != -1) elog(ERROR, "received unnamed record type as input"); /* Create a dummy PLyTypeInfo */ + cxt = AllocSetContextCreate(CurrentMemoryContext, + "PL/Python temp context", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); MemSet(&info, 0, sizeof(PLyTypeInfo)); - PLy_typeinfo_init(&info); + PLy_typeinfo_init(&info, cxt); /* Mark it as needing output routines lookup */ info.is_rowtype = 2; @@ -774,7 +776,7 @@ PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv) ReleaseTupleDesc(desc); - PLy_typeinfo_dealloc(&info); + MemoryContextDelete(cxt); return rv; } @@ -916,16 +918,22 @@ PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string) HeapTuple typeTup; PLyTypeInfo locinfo; PLyExecutionContext *exec_ctx = PLy_current_execution_context(); + MemoryContext cxt; /* Create a dummy PLyTypeInfo */ + cxt = AllocSetContextCreate(CurrentMemoryContext, + "PL/Python temp context", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); MemSet(&locinfo, 0, sizeof(PLyTypeInfo)); - PLy_typeinfo_init(&locinfo); + 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, typeTup, + PLy_output_datum_func2(&locinfo.out.d, locinfo.mcxt, typeTup, exec_ctx->curr_proc->langid, exec_ctx->curr_proc->trftypes); @@ -933,7 +941,7 @@ PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string) result = PLyObject_ToDatum(&locinfo.out.d, desc->tdtypmod, string); - PLy_typeinfo_dealloc(&locinfo); + MemoryContextDelete(cxt); return result; } @@ -1177,20 +1185,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 b01151b0fc0f5f1105817fa23e8da0b78a7517db..29fff61dc56b7df151de38a6aedc2a827350d903 100644 --- a/src/pl/plpython/plpy_typeio.h +++ b/src/pl/plpython/plpy_typeio.h @@ -88,10 +88,12 @@ typedef struct PLyTypeInfo Oid typ_relid; TransactionId typrel_xmin; ItemPointerData typrel_tid; + + /* context for subsidiary data (doesn't belong to this struct though) */ + MemoryContext mcxt; } PLyTypeInfo; -extern void PLy_typeinfo_init(PLyTypeInfo *arg); -extern void PLy_typeinfo_dealloc(PLyTypeInfo *arg); +extern void PLy_typeinfo_init(PLyTypeInfo *arg, MemoryContext mcxt); extern void PLy_input_datum_func(PLyTypeInfo *arg, Oid typeOid, HeapTuple typeTup, Oid langid, List *trftypes); extern void PLy_output_datum_func(PLyTypeInfo *arg, HeapTuple typeTup, Oid langid, List *trftypes); diff --git a/src/pl/plpython/plpy_util.c b/src/pl/plpython/plpy_util.c index b6b92557678cf20411c42b53d97178305a8a9638..f2d59491376d83c1d3e688173ecb00d6cc271527 100644 --- a/src/pl/plpython/plpy_util.c +++ b/src/pl/plpython/plpy_util.c @@ -17,42 +17,6 @@ #include "plpy_elog.h" -void * -PLy_malloc(size_t bytes) -{ - /* We need our allocations to be long-lived, so use TopMemoryContext */ - 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) -{ - pfree(ptr); -} - /* * Convert a Python unicode object to a Python string/bytes object in * PostgreSQL server encoding. Reference ownership is passed to the diff --git a/src/pl/plpython/plpy_util.h b/src/pl/plpython/plpy_util.h index 4c29f9aea3c176ea4701562adc5c2381945b5f74..66c5ccf8ac3dcac7809d3db669ab7a871ea1c86b 100644 --- a/src/pl/plpython/plpy_util.h +++ b/src/pl/plpython/plpy_util.h @@ -6,11 +6,6 @@ #ifndef PLPY_UTIL_H #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); extern char *PLyUnicode_AsString(PyObject *unicode);