OSDN Git Service

Rebuild cached function definition after CREATE OR REPLACE FUNCTION.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 22 Oct 2001 19:32:27 +0000 (19:32 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 22 Oct 2001 19:32:27 +0000 (19:32 +0000)
Fix typlen-vs-typmod errors inherited from pltcl.

src/pl/plpython/plpython.c

index 8dcfb1c..edb2d69 100644 (file)
@@ -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();