Rebuild cached function definition after CREATE OR REPLACE FUNCTION.

Fix typlen-vs-typmod errors inherited from pltcl.
This commit is contained in:
Tom Lane 2001-10-22 19:32:27 +00:00
parent b2e859a4fe
commit 970a2d1c91

View File

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