Commit 4a67565b authored by Tom Lane's avatar Tom Lane

Fix within-function memory leaks in the various PLs' interfaces to

SPI_prepare: they all save the prepared plan into topCxt, and so the
procCxt copy that's actually returned by SPI_prepare ought to be freed.
Diagnosis and plpython fix by Nigel Andrews, followup for other PLs
by Tom Lane.
parent 30c2b5ec
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.64 2002/09/05 00:43:07 tgl Exp $ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.65 2002/10/19 22:10:58 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -2018,6 +2018,7 @@ exec_prepare_plan(PLpgSQL_execstate * estate, ...@@ -2018,6 +2018,7 @@ exec_prepare_plan(PLpgSQL_execstate * estate,
expr->plan_simple_expr = NULL; expr->plan_simple_expr = NULL;
exec_simple_check_plan(expr); exec_simple_check_plan(expr);
SPI_freeplan(plan);
pfree(argtypes); pfree(argtypes);
} }
...@@ -2544,10 +2545,14 @@ exec_stmt_open(PLpgSQL_execstate * estate, PLpgSQL_stmt_open * stmt) ...@@ -2544,10 +2545,14 @@ exec_stmt_open(PLpgSQL_execstate * estate, PLpgSQL_stmt_open * stmt)
* ---------- * ----------
*/ */
curplan = SPI_prepare(querystr, 0, NULL); curplan = SPI_prepare(querystr, 0, NULL);
if (curplan == NULL)
elog(ERROR, "SPI_prepare() failed for dynamic query \"%s\"",
querystr);
portal = SPI_cursor_open(curname, curplan, NULL, NULL); portal = SPI_cursor_open(curname, curplan, NULL, NULL);
if (portal == NULL) if (portal == NULL)
elog(ERROR, "Failed to open cursor"); elog(ERROR, "Failed to open cursor");
pfree(querystr); pfree(querystr);
SPI_freeplan(curplan);
/* ---------- /* ----------
* Store the eventually assigned cursor name in the cursor variable * Store the eventually assigned cursor name in the cursor variable
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.25 2002/10/14 04:20:52 momjian Exp $ * $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.26 2002/10/19 22:10:58 tgl Exp $
* *
********************************************************************* *********************************************************************
*/ */
...@@ -1837,21 +1837,7 @@ PLy_plan_dealloc(PyObject * arg) ...@@ -1837,21 +1837,7 @@ PLy_plan_dealloc(PyObject * arg)
enter(); enter();
if (ob->plan) if (ob->plan)
{ SPI_freeplan(ob->plan);
/*
* free the plan... pfree(ob->plan);
*
* FIXME -- leaks saved plan on object destruction. can this be
* avoided?
* I think so. A function prepares and then execp's a statement.
* When we come to deallocate the 'statement' object we obviously
* no long need the plan. Even if we did, without the object
* we're never going to be able to use it again.
* In the against arguments: SPI_saveplan has stuck this under
* the top context so there must be a reason for doing that.
*/
pfree(ob->plan);
}
if (ob->types) if (ob->types)
PLy_free(ob->types); PLy_free(ob->types);
if (ob->args) if (ob->args)
...@@ -2023,6 +2009,7 @@ PLy_spi_prepare(PyObject * self, PyObject * args) ...@@ -2023,6 +2009,7 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
PyObject *list = NULL; PyObject *list = NULL;
PyObject *volatile optr = NULL; PyObject *volatile optr = NULL;
char *query; char *query;
void *tmpplan;
enter(); enter();
...@@ -2062,7 +2049,6 @@ PLy_spi_prepare(PyObject * self, PyObject * args) ...@@ -2062,7 +2049,6 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
int nargs, int nargs,
i; i;
nargs = PySequence_Length(list); nargs = PySequence_Length(list);
if (nargs > 0) if (nargs > 0)
{ {
...@@ -2125,7 +2111,10 @@ PLy_spi_prepare(PyObject * self, PyObject * args) ...@@ -2125,7 +2111,10 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
RAISE_EXC(1); RAISE_EXC(1);
} }
plan->plan = SPI_saveplan(plan->plan); /* transfer plan from procCxt to topCxt */
tmpplan = plan->plan;
plan->plan = SPI_saveplan(tmpplan);
SPI_freeplan(tmpplan);
if (plan->plan == NULL) if (plan->plan == NULL)
{ {
PLy_exception_set(PLy_exc_spi_error, PLy_exception_set(PLy_exc_spi_error,
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* ENHANCEMENTS, OR MODIFICATIONS. * ENHANCEMENTS, OR MODIFICATIONS.
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.65 2002/10/14 04:20:52 momjian Exp $ * $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.66 2002/10/19 22:10:58 tgl Exp $
* *
**********************************************************************/ **********************************************************************/
...@@ -1285,7 +1285,7 @@ pltcl_elog(ClientData cdata, Tcl_Interp *interp, ...@@ -1285,7 +1285,7 @@ pltcl_elog(ClientData cdata, Tcl_Interp *interp,
else if (strcmp(argv[1], "NOTICE") == 0) else if (strcmp(argv[1], "NOTICE") == 0)
level = NOTICE; level = NOTICE;
else if (strcmp(argv[1], "WARNING") == 0) else if (strcmp(argv[1], "WARNING") == 0)
level = ERROR; level = WARNING;
else if (strcmp(argv[1], "ERROR") == 0) else if (strcmp(argv[1], "ERROR") == 0)
level = ERROR; level = ERROR;
else if (strcmp(argv[1], "FATAL") == 0) else if (strcmp(argv[1], "FATAL") == 0)
...@@ -1837,7 +1837,8 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp, ...@@ -1837,7 +1837,8 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
} }
/************************************************************ /************************************************************
* Save the plan * Save the plan into permanent memory (right now it's in the
* SPI procCxt, which will go away at function end).
************************************************************/ ************************************************************/
qdesc->plan = SPI_saveplan(plan); qdesc->plan = SPI_saveplan(plan);
if (qdesc->plan == NULL) if (qdesc->plan == NULL)
...@@ -1866,6 +1867,8 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp, ...@@ -1866,6 +1867,8 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
elog(ERROR, "pltcl: SPI_saveplan() failed - %s", reason); elog(ERROR, "pltcl: SPI_saveplan() failed - %s", reason);
} }
/* Release the procCxt copy to avoid within-function memory leak */
SPI_freeplan(plan);
/************************************************************ /************************************************************
* Insert a hashtable entry for the plan and return * Insert a hashtable entry for the plan and return
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment