From 970a2d1c91b4e4e1d81516ebc8802f1dfcf11622 Mon Sep 17 00:00:00 2001 From: Tom Lane 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 8dcfb1c970..edb2d69a9f 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(); -- 2.11.0