* 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 $
*
*********************************************************************
*/
typedef struct PLyDatumToOb {
PLyDatumToObFunc func;
FmgrInfo typfunc;
- Oid typoutput;
Oid typelem;
- int2 typlen;
+ bool typbyval;
} PLyDatumToOb;
typedef struct PLyTupleToOb {
typedef struct PLyObToDatum {
FmgrInfo typfunc;
Oid typelem;
- int2 typlen;
+ bool typbyval;
} PLyObToDatum;
typedef struct PLyObToTuple {
*/
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;
/* 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);
/* 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 *);
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",
* 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();
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;
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);
}
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();
/* 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();
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();
}
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();
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);
/* 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;
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())
{
PointerGetDatum(&procStruct->prosrc));
procSource = DatumGetCString(procDatum);
- ReleaseSysCache(procTup);
-
PLy_procedure_compile(proc, procSource);
pfree(procSource);
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)
{
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
{
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
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
DECLARE_EXC();
PLyPlanObject *plan;
PyObject *list = NULL;
- PyObject *optr = NULL;
+ PyObject * volatile optr = NULL;
char *query;
enter();
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();
*/
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;
}
}
{
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);
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;
}
}
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();