]> granicus.if.org Git - postgresql/commitdiff
pltcl, plperl, and plpython all suffer the same bug previously fixed
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 1 Jun 2001 18:17:44 +0000 (18:17 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 1 Jun 2001 18:17:44 +0000 (18:17 +0000)
in plpgsql: they fail for datatypes that have old-style I/O functions
due to caching FmgrInfo structs with wrong fn_mcxt lifetime.

Although the plpython fix seems straightforward, I can't check it here
since I don't have Python installed --- would someone check it?

src/pl/plperl/plperl.c
src/pl/plpython/plpython.c
src/pl/tcl/pltcl.c

index 091b4e4071d3760541836817b01493c9faeee587..bb9ab670ae626e38bd4fb828256e98429a9bf26d 100644 (file)
@@ -33,7 +33,7 @@
  *       ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/pl/plperl/plperl.c,v 1.19 2001/03/22 04:01:40 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/plperl/plperl.c,v 1.20 2001/06/01 18:17:44 tgl Exp $
  *
  **********************************************************************/
 
@@ -163,6 +163,27 @@ static void plperl_set_tuple_values(Tcl_Interp *interp, char *arrayname,
 #endif
 
 
+/*
+ * This routine is a crock, and so is everyplace that calls it.  The problem
+ * is that the cached form of plperl 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 must be called in 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)
+{
+       MemoryContext   oldcontext;
+
+       oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+       fmgr_info(functionId, finfo);
+       MemoryContextSwitchTo(oldcontext);
+}
+
 /**********************************************************************
  * plperl_init_all()           - Initialize all
  **********************************************************************/
@@ -562,7 +583,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
                        elog(ERROR, "plperl: return types of tuples not supported yet");
                }
 
-               fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
+               perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
                prodesc->result_in_elem = (Oid) (typeStruct->typelem);
                prodesc->result_in_len = typeStruct->typlen;
 
@@ -595,7 +616,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
                        else
                                prodesc->arg_is_rel[i] = 0;
 
-                       fmgr_info(typeStruct->typoutput, &(prodesc->arg_out_func[i]));
+                       perm_fmgr_info(typeStruct->typoutput, &(prodesc->arg_out_func[i]));
                        prodesc->arg_out_elem[i] = (Oid) (typeStruct->typelem);
                        prodesc->arg_out_len[i] = typeStruct->typlen;
                        ReleaseSysCache(typeTup);
@@ -1560,8 +1581,8 @@ plperl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
                if (!HeapTupleIsValid(typeTup))
                        elog(ERROR, "plperl: Cache lookup of type %s failed", args[i]);
                qdesc->argtypes[i] = typeTup->t_data->t_oid;
-               fmgr_info(((Form_pg_type) GETSTRUCT(typeTup))->typinput,
-                                 &(qdesc->arginfuncs[i]));
+               perm_fmgr_info(((Form_pg_type) GETSTRUCT(typeTup))->typinput,
+                                          &(qdesc->arginfuncs[i]));
                qdesc->argtypelems[i] = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
                qdesc->argvalues[i] = (Datum) NULL;
                qdesc->arglen[i] = (int) (((Form_pg_type) GETSTRUCT(typeTup))->typlen);
index dea0dc285f894a1f1cace279fa402eb623203647..ea0b7d5ed9175a065561a75a390e738846206abc 100644 (file)
@@ -1,10 +1,6 @@
-/* $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.3 2001/05/25 15:48:33 momjian Exp $ */
-
-/*
+/**********************************************************************
  * plpython.c - python as a procedural language for PostgreSQL
  *
- * IDENTIFICATION
- *
  * This software is copyright by Andrew Bosma
  * but is really shameless cribbed from pltcl.c by Jan Weick, and
  * plperl.c by Mark Hollomon.
  * AND THE AUTHOR AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
- **********************************************************************/
+ * IDENTIFICATION
+ *     $Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.4 2001/06/01 18:17:44 tgl Exp $
+ *
+ *********************************************************************
+ */
 
 #include "postgres.h"
 
@@ -296,8 +296,32 @@ volatile int func_enter_calls = 0;
 volatile int func_leave_calls = 0;
 #endif
 
-/* the function definitions
+/*
+ * the function definitions
  */
+
+/*
+ * 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 must be called in 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)
+{
+       MemoryContext   oldcontext;
+
+       oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+       fmgr_info(functionId, finfo);
+       MemoryContextSwitchTo(oldcontext);
+}
+
+
 Datum
 plpython_call_handler(PG_FUNCTION_ARGS)
 {
@@ -1282,7 +1306,7 @@ PLy_output_datum_func2(PLyObToDatum *arg, Form_pg_type typeStruct)
 {
   enter();
 
-  fmgr_info(typeStruct->typinput, &arg->typfunc);
+  perm_fmgr_info(typeStruct->typinput, &arg->typfunc);
   arg->typelem = (Oid) typeStruct->typelem;
   arg->typlen = typeStruct->typlen;
 }
@@ -1304,7 +1328,7 @@ PLy_input_datum_func2(PLyDatumToOb *arg, Form_pg_type typeStruct)
   char *type;
 
   arg->typoutput = typeStruct->typoutput;
-  fmgr_info(typeStruct->typoutput, &arg->typfunc);
+  perm_fmgr_info(typeStruct->typoutput, &arg->typfunc);
   arg->typlen = typeStruct->typlen;
   arg->typelem = typeStruct->typelem;
 
index 5c44cbe7abc9edc51c4284b846ea19fb1fa74c52..30985a434c1a93be4b55f78a99506f4894b457b4 100644 (file)
@@ -31,7 +31,7 @@
  *       ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.35 2001/05/11 23:38:06 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.36 2001/06/01 18:17:44 tgl Exp $
  *
  **********************************************************************/
 
@@ -145,6 +145,27 @@ static void pltcl_set_tuple_values(Tcl_Interp *interp, char *arrayname,
 static void pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc,
                                                   Tcl_DString *retval);
 
+/*
+ * This routine is a crock, and so is everyplace that calls it.  The problem
+ * is that the cached form of pltcl 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 must be called in 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)
+{
+       MemoryContext   oldcontext;
+
+       oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+       fmgr_info(functionId, finfo);
+       MemoryContextSwitchTo(oldcontext);
+}
+
 /**********************************************************************
  * pltcl_init_all()            - Initialize all
  **********************************************************************/
@@ -508,7 +529,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
                        elog(ERROR, "pltcl: return types of tuples not supported yet");
                }
 
-               fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
+               perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
                prodesc->result_in_elem = typeStruct->typelem;
 
                ReleaseSysCache(typeTup);
@@ -549,7 +570,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
                        else
                                prodesc->arg_is_rel[i] = 0;
 
-                       fmgr_info(typeStruct->typoutput, &(prodesc->arg_out_func[i]));
+                       perm_fmgr_info(typeStruct->typoutput, &(prodesc->arg_out_func[i]));
                        prodesc->arg_out_elem[i] = (Oid) (typeStruct->typelem);
                        prodesc->arg_out_len[i] = typeStruct->typlen;
 
@@ -1760,8 +1781,8 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
                if (!HeapTupleIsValid(typeTup))
                        elog(ERROR, "pltcl: Cache lookup of type %s failed", args[i]);
                qdesc->argtypes[i] = typeTup->t_data->t_oid;
-               fmgr_info(((Form_pg_type) GETSTRUCT(typeTup))->typinput,
-                                 &(qdesc->arginfuncs[i]));
+               perm_fmgr_info(((Form_pg_type) GETSTRUCT(typeTup))->typinput,
+                                          &(qdesc->arginfuncs[i]));
                qdesc->argtypelems[i] = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
                qdesc->argvalues[i] = (Datum) NULL;
                qdesc->arglen[i] = (int) (((Form_pg_type) GETSTRUCT(typeTup))->typlen);