aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pl/plpython/plpy_cursorobject.c30
-rw-r--r--src/pl/plpython/plpy_cursorobject.h1
-rw-r--r--src/pl/plpython/plpy_exec.c2
-rw-r--r--src/pl/plpython/plpy_main.c39
-rw-r--r--src/pl/plpython/plpy_main.h3
-rw-r--r--src/pl/plpython/plpy_planobject.c19
-rw-r--r--src/pl/plpython/plpy_planobject.h1
-rw-r--r--src/pl/plpython/plpy_procedure.c118
-rw-r--r--src/pl/plpython/plpy_procedure.h2
-rw-r--r--src/pl/plpython/plpy_spi.c30
-rw-r--r--src/pl/plpython/plpy_subxactobject.c15
-rw-r--r--src/pl/plpython/plpy_typeio.c137
-rw-r--r--src/pl/plpython/plpy_typeio.h6
-rw-r--r--src/pl/plpython/plpy_util.c36
-rw-r--r--src/pl/plpython/plpy_util.h5
15 files changed, 221 insertions, 223 deletions
diff --git a/src/pl/plpython/plpy_cursorobject.c b/src/pl/plpython/plpy_cursorobject.c
index 2c458d35fdb..103571ba15c 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 3c28f4f8e71..c73033c486b 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 3ccebe403e4..24aed011e4b 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 63a284e2384..3c2ebfa16af 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 b13e2c21a11..10426c43236 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 8305bd68e96..a9040efb502 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 7a89ffc2c18..c67559266ec 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 16ff84560bb..e1f56209ef0 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 6d4b00ba7c8..9fc8db07972 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 d0e255f8359..58e78ecebcb 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 2e7ec4fdab4..81fb3a3a4ab 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 05add6e2ce8..7ad7a4400a5 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 b01151b0fc0..29fff61dc56 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 b6b92557678..f2d59491376 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 4c29f9aea3c..66c5ccf8ac3 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);