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.
*
* 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();