From 970a2d1c91b4e4e1d81516ebc8802f1dfcf11622 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Mon, 22 Oct 2001 19:32:27 +0000
Subject: [PATCH] Rebuild cached function definition after CREATE OR REPLACE
 FUNCTION. Fix typlen-vs-typmod errors inherited from pltcl.

---
 src/pl/plpython/plpython.c | 234 +++++++++++++++++++------------------
 1 file changed, 121 insertions(+), 113 deletions(-)

diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c
index 8dcfb1c970c..edb2d69a9fe 100644
--- a/src/pl/plpython/plpython.c
+++ b/src/pl/plpython/plpython.c
@@ -29,7 +29,7 @@
  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *	$Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.8 2001/10/06 23:21:45 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/pl/plpython/plpython.c,v 1.9 2001/10/22 19:32:27 tgl Exp $
  *
  *********************************************************************
  */
@@ -73,9 +73,8 @@ typedef PyObject *(*PLyDatumToObFunc) (const char *);
 typedef struct PLyDatumToOb {
   PLyDatumToObFunc func;
   FmgrInfo typfunc;
-  Oid typoutput;
   Oid typelem;
-  int2 typlen;
+  bool typbyval;
 } PLyDatumToOb;
 
 typedef struct PLyTupleToOb {
@@ -94,7 +93,7 @@ typedef union PLyTypeInput {
 typedef struct PLyObToDatum {
   FmgrInfo typfunc;
   Oid typelem;
-  int2 typlen;
+  bool typbyval;
 } PLyObToDatum;
 
 typedef struct PLyObToTuple {
@@ -121,6 +120,8 @@ typedef struct PLyTypeInfo {
  */
 typedef struct PLyProcedure {
   char *proname;
+  TransactionId fn_xmin;
+  CommandId fn_cmin;
   PLyTypeInfo result; /* also used to store info for trigger tuple type */
   PLyTypeInfo args[FUNC_MAX_ARGS];
   int nargs;
@@ -192,11 +193,11 @@ static void PLy_free(void *);
 
 /* sub handlers for functions and triggers
  */
-static Datum PLy_function_handler(PG_FUNCTION_ARGS, PLyProcedure *);
-static HeapTuple PLy_trigger_handler(PG_FUNCTION_ARGS, PLyProcedure *);
+static Datum PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *);
+static HeapTuple PLy_trigger_handler(FunctionCallInfo fcinfo, PLyProcedure *);
 
-static PyObject *PLy_function_build_args(PG_FUNCTION_ARGS, PLyProcedure *);
-static PyObject *PLy_trigger_build_args(PG_FUNCTION_ARGS, PLyProcedure *,
+static PyObject *PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *);
+static PyObject *PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *,
 					HeapTuple *);
 static HeapTuple PLy_modify_tuple(PLyProcedure *, PyObject *,
 				  TriggerData *, HeapTuple);
@@ -206,12 +207,14 @@ static PyObject *PLy_procedure_call(PLyProcedure *, char *, PyObject *);
 /* returns a cached PLyProcedure, or creates, stores and returns
  * a new PLyProcedure.
  */
-static PLyProcedure *PLy_procedure_get(PG_FUNCTION_ARGS, bool);
+static PLyProcedure *PLy_procedure_get(FunctionCallInfo fcinfo, bool);
+
+static PLyProcedure *PLy_procedure_create(FunctionCallInfo fcinfo,
+										  bool is_trigger,
+										  HeapTuple procTup, char *key);
 
-static PLyProcedure *PLy_procedure_create(PG_FUNCTION_ARGS, bool, char *);
 static void PLy_procedure_compile(PLyProcedure *, const char *);
 static char *PLy_procedure_munge_source(const char *, const char *);
-static PLyProcedure *PLy_procedure_new(const char *name);
 static void PLy_procedure_delete(PLyProcedure *);
 
 static void PLy_typeinfo_init(PLyTypeInfo *);
@@ -249,7 +252,6 @@ static PyObject *PLy_interp_safe = NULL;
 static PyObject *PLy_interp_safe_globals = NULL;
 static PyObject *PLy_importable_modules = NULL;
 static PyObject *PLy_procedure_cache = NULL;
-static char *PLy_procedure_fmt = "__plpython_procedure_%s_%u";
 
 char *PLy_importable_modules_list[] = {
   "array",
@@ -387,12 +389,12 @@ plpython_call_handler(PG_FUNCTION_ARGS)
  * to take no arguments and return an argument of type opaque.
  */
 HeapTuple
-PLy_trigger_handler(PG_FUNCTION_ARGS, PLyProcedure *proc)
+PLy_trigger_handler(FunctionCallInfo fcinfo, PLyProcedure *proc)
 {
   DECLARE_EXC();
   HeapTuple rv = NULL;
-  PyObject *plargs = NULL;
-  PyObject *plrv = NULL;
+  PyObject * volatile plargs = NULL;
+  PyObject * volatile plrv = NULL;
 
   enter();
 
@@ -468,12 +470,16 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
 		 HeapTuple otup)
 {
   DECLARE_EXC();
-  PyObject *plntup, *plkeys, *platt, *plval, *plstr;
+  PyObject * volatile plntup;
+  PyObject * volatile plkeys;
+  PyObject * volatile platt;
+  PyObject * volatile plval;
+  PyObject * volatile plstr;
   HeapTuple rtup;
   int natts, i, j, attn, atti;
-  int *modattrs;
-  Datum *modvalues;
-  char *modnulls;
+  int * volatile modattrs;
+  Datum * volatile modvalues;
+  char *volatile modnulls;
   TupleDesc tupdesc;
 
   plntup = plkeys = platt = plval = plstr = NULL;
@@ -556,8 +562,8 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
 
 	  modvalues[j] = FunctionCall3(&proc->result.out.r.atts[atti].typfunc,
 				       CStringGetDatum(src),
-				       proc->result.out.r.atts[atti].typelem,
-				       proc->result.out.r.atts[atti].typlen);
+				       ObjectIdGetDatum(proc->result.out.r.atts[atti].typelem),
+								   Int32GetDatum(tupdesc->attrs[j]->atttypmod));
 	  modnulls[j] = ' ';
 	  
 	  Py_DECREF(plstr);
@@ -588,13 +594,13 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
 }
 
 PyObject *
-PLy_trigger_build_args(PG_FUNCTION_ARGS, PLyProcedure *proc, HeapTuple *rv)
+PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *rv)
 {
   DECLARE_EXC();
   TriggerData *tdata;
   PyObject *pltname, *pltevent, *pltwhen, *pltlevel, *pltrelid;
   PyObject *pltargs, *pytnew, *pytold;
-  PyObject *pltdata = NULL;  
+  PyObject * volatile pltdata = NULL;  
   char *stroid;
 
   enter();
@@ -723,13 +729,13 @@ PLy_trigger_build_args(PG_FUNCTION_ARGS, PLyProcedure *proc, HeapTuple *rv)
 /* function handler and friends
  */
 Datum
-PLy_function_handler(PG_FUNCTION_ARGS, PLyProcedure *proc)
+PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure *proc)
 {
   DECLARE_EXC();
   Datum rv;
-  PyObject *plargs = NULL;
-  PyObject *plrv = NULL;
-  PyObject *plrv_so = NULL;
+  PyObject * volatile plargs = NULL;
+  PyObject * volatile plrv = NULL;
+  PyObject * volatile plrv_so = NULL;
   char *plrv_sc;
 
   enter();
@@ -792,9 +798,9 @@ PLy_function_handler(PG_FUNCTION_ARGS, PLyProcedure *proc)
       plrv_so = PyObject_Str(plrv);
       plrv_sc = PyString_AsString(plrv_so);
       rv = FunctionCall3(&proc->result.out.d.typfunc,
-			 PointerGetDatum(plrv_sc),
-			 proc->result.out.d.typelem,
-			 proc->result.out.d.typlen);
+						 PointerGetDatum(plrv_sc),
+						 ObjectIdGetDatum(proc->result.out.d.typelem),
+						 Int32GetDatum(-1));
     }
 
   RESTORE_EXC();
@@ -828,11 +834,11 @@ PLy_procedure_call(PLyProcedure *proc, char *kargs, PyObject *vargs)
 }
 
 PyObject *
-PLy_function_build_args(PG_FUNCTION_ARGS, PLyProcedure *proc)
+PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
 {
   DECLARE_EXC();
-  PyObject *arg = NULL;
-  PyObject *args = NULL;
+  PyObject * volatile arg = NULL;
+  PyObject * volatile args = NULL;
   int i;
 
   enter();
@@ -868,9 +874,9 @@ PLy_function_build_args(PG_FUNCTION_ARGS, PLyProcedure *proc)
 	      Datum dt;
 
 	      dt = FunctionCall3(&(proc->args[i].in.d.typfunc),
-				 fcinfo->arg[i],
-				 proc->args[i].in.d.typelem,
-				 proc->args[i].in.d.typlen);
+							 fcinfo->arg[i],
+							 ObjectIdGetDatum(proc->args[i].in.d.typelem),
+							 Int32GetDatum(-1));
 	      ct = DatumGetCString(dt);
 	      arg = (proc->args[i].in.d.func)(ct);
 	      pfree(ct);
@@ -898,45 +904,68 @@ PLy_function_build_args(PG_FUNCTION_ARGS, PLyProcedure *proc)
 
 /* PLyProcedure functions
  */
-PLyProcedure *
-PLy_procedure_get(PG_FUNCTION_ARGS, bool is_trigger)
+static PLyProcedure *
+PLy_procedure_get(FunctionCallInfo fcinfo, bool is_trigger)
 {
+  Oid fn_oid;
+  HeapTuple procTup;
   char key[128];
   PyObject *plproc;
-  PLyProcedure *proc;
+  PLyProcedure *proc = NULL;
   int rv;
 
   enter();
 
-  rv = snprintf(key, sizeof(key), "%u", fcinfo->flinfo->fn_oid);
+  fn_oid = fcinfo->flinfo->fn_oid;
+  procTup = SearchSysCache(PROCOID,
+						   ObjectIdGetDatum(fn_oid),
+						   0, 0, 0);
+  if (!HeapTupleIsValid(procTup))
+	  elog(ERROR, "plpython: cache lookup for procedure %u failed", fn_oid);
+
+  rv = snprintf(key, sizeof(key), "%u%s",
+				fn_oid,
+				is_trigger ? "_trigger" : "");
   if ((rv >= sizeof(key)) || (rv < 0))
     elog(FATAL, "plpython: Buffer overrun in %s:%d", __FILE__, __LINE__);
   
   plproc = PyDict_GetItemString(PLy_procedure_cache, key);
-  if (plproc == NULL)
-    return PLy_procedure_create(fcinfo, is_trigger, key);
 
-  Py_INCREF(plproc);
-  if (!PyCObject_Check(plproc))
-    elog(FATAL, "plpython: Expected a PyCObject, didn't get one");
+  if (plproc != NULL)
+  {
+	  Py_INCREF(plproc);
+	  if (!PyCObject_Check(plproc))
+		  elog(FATAL, "plpython: Expected a PyCObject, didn't get one");
 
-  mark();
+	  mark();
 
-  proc = PyCObject_AsVoidPtr(plproc);
-  if (proc->me != plproc)
-    elog(FATAL, "plpython: Aiieee, proc->me != plproc");
+	  proc = PyCObject_AsVoidPtr(plproc);
+	  if (proc->me != plproc)
+		  elog(FATAL, "plpython: Aiieee, proc->me != plproc");
+	  /* did we find an up-to-date cache entry? */
+	  if (proc->fn_xmin != procTup->t_data->t_xmin ||
+		  proc->fn_cmin != procTup->t_data->t_cmin)
+	  {
+		  Py_DECREF(plproc);
+		  proc = NULL;
+	  }
+  }
+
+  if (proc == NULL)
+	  proc = PLy_procedure_create(fcinfo, is_trigger, procTup, key);
+
+  ReleaseSysCache(procTup);
 
   return proc;
 }
 
-PLyProcedure *
-PLy_procedure_create(PG_FUNCTION_ARGS, bool is_trigger, char *key)
+static PLyProcedure *
+PLy_procedure_create(FunctionCallInfo fcinfo, bool is_trigger,
+					 HeapTuple procTup, char *key)
 {
   char procName[256];
   DECLARE_EXC();
-  HeapTuple procTup;
   Form_pg_proc procStruct;
-  Oid fn_oid;
   PLyProcedure *volatile proc;
   char *volatile procSource = NULL;
   Datum procDatum;
@@ -944,19 +973,28 @@ PLy_procedure_create(PG_FUNCTION_ARGS, bool is_trigger, char *key)
 
   enter();
 
-  fn_oid = fcinfo->flinfo->fn_oid;
-  procTup = SearchSysCache(PROCOID, ObjectIdGetDatum(fn_oid), 0, 0, 0);
-  if (!HeapTupleIsValid(procTup))
-    elog(ERROR, "plpython: cache lookup for procedure \"%u\" failed", fn_oid);
   procStruct = (Form_pg_proc) GETSTRUCT(procTup);
 
-  rv = snprintf(procName, sizeof(procName), PLy_procedure_fmt,
-		NameStr(procStruct->proname), fn_oid);
+  rv = snprintf(procName, sizeof(procName),
+				"__plpython_procedure_%s_%u%s",
+				NameStr(procStruct->proname),
+				fcinfo->flinfo->fn_oid,
+				is_trigger ? "_trigger" : "");
   if ((rv >= sizeof(procName)) || (rv < 0))
     elog(FATAL, "plpython: Procedure name would overrun buffer");
 
-  proc = PLy_procedure_new(procName);
-  
+  proc = PLy_malloc(sizeof(PLyProcedure));
+  proc->proname = PLy_malloc(strlen(procName) + 1);
+  strcpy(proc->proname, procName);
+  proc->fn_xmin = procTup->t_data->t_xmin;
+  proc->fn_cmin = procTup->t_data->t_cmin;
+  PLy_typeinfo_init(&proc->result);
+  for (i = 0; i < FUNC_MAX_ARGS; i++)
+    PLy_typeinfo_init(&proc->args[i]);
+  proc->nargs = 0;
+  proc->code = proc->interp = proc->reval = proc->statics = NULL;
+  proc->globals = proc->me = NULL;
+
   SAVE_EXC();
   if (TRAP_EXC())
     {
@@ -1037,8 +1075,6 @@ PLy_procedure_create(PG_FUNCTION_ARGS, bool is_trigger, char *key)
 				  PointerGetDatum(&procStruct->prosrc));
   procSource = DatumGetCString(procDatum);
 
-  ReleaseSysCache(procTup);
-
   PLy_procedure_compile(proc, procSource);
 
   pfree(procSource);
@@ -1170,29 +1206,6 @@ PLy_procedure_munge_source(const char *name, const char *src)
   return mrc;
 }
 
-PLyProcedure *
-PLy_procedure_new(const char *name)
-{
-  int i;
-  PLyProcedure *proc;
-
-  enter();
-  
-  proc = PLy_malloc(sizeof(PLyProcedure));
-  proc->proname = PLy_malloc(strlen(name) + 1);
-  strcpy(proc->proname, name);
-  PLy_typeinfo_init(&proc->result);
-  for (i = 0; i < FUNC_MAX_ARGS; i++)
-    PLy_typeinfo_init(&proc->args[i]);
-  proc->nargs = 0;
-  proc->code = proc->interp = proc->reval = proc->statics = NULL;
-  proc->globals = proc->me = NULL;
-
-  leave();
-
-  return proc;
-}
-
 void
 PLy_procedure_delete(PLyProcedure *proc)
 {
@@ -1314,8 +1327,8 @@ PLy_output_datum_func2(PLyObToDatum *arg, Form_pg_type typeStruct)
   enter();
 
   perm_fmgr_info(typeStruct->typinput, &arg->typfunc);
-  arg->typelem = (Oid) typeStruct->typelem;
-  arg->typlen = typeStruct->typlen;
+  arg->typelem = typeStruct->typelem;
+  arg->typbyval = typeStruct->typbyval;
 }
 
 void
@@ -1334,10 +1347,9 @@ PLy_input_datum_func2(PLyDatumToOb *arg, Form_pg_type typeStruct)
 {
   char *type;
 
-  arg->typoutput = typeStruct->typoutput;
   perm_fmgr_info(typeStruct->typoutput, &arg->typfunc);
-  arg->typlen = typeStruct->typlen;
   arg->typelem = typeStruct->typelem;
+  arg->typbyval = typeStruct->typbyval;
 
   /* hmmm, wierd.  means this arg will always be converted
    * to a python None
@@ -1516,9 +1528,10 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
 	PyDict_SetItemString(dict, key, Py_None);
       else
 	{
-	  vdat = OidFunctionCall3(info->in.r.atts[i].typoutput, vattr,
-				  ObjectIdGetDatum(info->in.r.atts[i].typelem),
-				  Int32GetDatum(info->in.r.atts[i].typlen));
+	  vdat = FunctionCall3(&info->in.r.atts[i].typfunc,
+						   vattr,
+						   ObjectIdGetDatum(info->in.r.atts[i].typelem),
+						   Int32GetDatum(desc->attrs[i]->atttypmod));
 	  vsrc = DatumGetCString(vdat);
 
 	  /* no exceptions allowed
@@ -1873,7 +1886,7 @@ PLy_spi_prepare(PyObject *self, PyObject *args)
   DECLARE_EXC();
   PLyPlanObject *plan;
   PyObject *list = NULL;
-  PyObject *optr = NULL;
+  PyObject * volatile optr = NULL;
   char *query;
 
   enter();
@@ -2037,7 +2050,8 @@ PyObject *
 PLy_spi_execute_plan(PyObject *ob, PyObject *list, int limit)
 {
   DECLARE_EXC();
-  int nargs, i, rv;
+  volatile int nargs;
+  int i, rv;
   PLyPlanObject *plan;
 
   enter();
@@ -2080,12 +2094,10 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, int limit)
        */
       for (i = 0; i < nargs; i++)
 	{
-	  /* FIXME -- typbyval the proper check?
-	   */
-	  if ((plan->values[i] != (Datum) NULL) &&
-	      (plan->args[i].out.d.typlen < 0))
-	    {
-	      pfree((void *) plan->values[i]);
+	  if (!plan->args[i].out.d.typbyval &&
+		  (plan->values[i] != (Datum) NULL))
+	  {
+	      pfree(DatumGetPointer(plan->values[i]));
 	      plan->values[i] = (Datum) NULL;
 	    }
 	}
@@ -2100,21 +2112,19 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, int limit)
     {
       for (i = 0; i < nargs; i++)
 	{
-	  Datum typelem, typlen, dv;
 	  PyObject *elem, *so;
 	  char *sv;
 
-	  typelem = ObjectIdGetDatum(plan->args[i].out.d.typelem);
-	  typlen = Int32GetDatum(plan->args[i].out.d.typlen);
 	  elem = PySequence_GetItem(list, i);
 	  so = PyObject_Str(elem);
 	  sv = PyString_AsString(so);
-	  dv = CStringGetDatum(sv);
 
 	  /* FIXME -- if this can elog, we have leak
 	   */
 	  plan->values[i] = FunctionCall3(&(plan->args[i].out.d.typfunc),
-					  dv, typelem, typlen);
+									  CStringGetDatum(sv),
+									  ObjectIdGetDatum(plan->args[i].out.d.typelem),
+									  Int32GetDatum(-1));
 
 	  Py_DECREF(so);
 	  Py_DECREF(elem);
@@ -2126,12 +2136,10 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, int limit)
 
   for (i = 0; i < nargs; i++)
     {
-      /* FIXME -- typbyval the proper check?
-       */
-      if ((plan->values[i] != (Datum) NULL) &&
-	  (plan->args[i].out.d.typlen < 0))
+      if (!plan->args[i].out.d.typbyval &&
+		  (plan->values[i] != (Datum) NULL))
 	{
-	  pfree((void *) plan->values[i]);
+	  pfree(DatumGetPointer(plan->values[i]));
 	  plan->values[i] = (Datum) NULL;
 	}
     }
@@ -2413,11 +2421,11 @@ PLy_notice(PyObject *self, PyObject *args)
 
 
 PyObject *
-PLy_log(int level, PyObject *self, PyObject *args)
+PLy_log(volatile int level, PyObject *self, PyObject *args)
 {
   DECLARE_EXC();
   PyObject *so;
-  char *sv;
+  char * volatile sv;
 
   enter();
 
-- 
GitLab