aboutsummaryrefslogtreecommitdiff
path: root/src/pl/plpython/plpython.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pl/plpython/plpython.c')
-rw-r--r--src/pl/plpython/plpython.c981
1 files changed, 491 insertions, 490 deletions
diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c
index 07eed862477..45340d0ed89 100644
--- a/src/pl/plpython/plpython.c
+++ b/src/pl/plpython/plpython.c
@@ -29,7 +29,7 @@
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.53 2004/08/05 03:10:29 joe Exp $
+ * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.54 2004/08/29 05:07:01 momjian Exp $
*
*********************************************************************
*/
@@ -115,12 +115,10 @@ typedef struct PLyTypeInfo
PLyTypeInput in;
PLyTypeOutput out;
int is_rowtype;
+
/*
- * is_rowtype can be:
- * -1 not known yet (initial state)
- * 0 scalar datatype
- * 1 rowtype
- * 2 rowtype, but I/O functions not set up yet
+ * is_rowtype can be: -1 not known yet (initial state) 0 scalar
+ * datatype 1 rowtype 2 rowtype, but I/O functions not set up yet
*/
} PLyTypeInfo;
@@ -161,7 +159,7 @@ typedef struct PLyResultObject
{
PyObject_HEAD
/* HeapTuple *tuples; */
- PyObject *nrows; /* number of rows returned by query */
+ PyObject * nrows; /* number of rows returned by query */
PyObject *rows; /* data rows, or None if no data returned */
PyObject *status; /* query status, SPI_OK_*, or SPI_ERR_* */
} PLyResultObject;
@@ -225,7 +223,7 @@ static HeapTuple PLy_modify_tuple(PLyProcedure *, PyObject *,
static PyObject *PLy_procedure_call(PLyProcedure *, char *, PyObject *);
static PLyProcedure *PLy_procedure_get(FunctionCallInfo fcinfo,
- Oid tgreloid);
+ Oid tgreloid);
static PLyProcedure *PLy_procedure_create(FunctionCallInfo fcinfo,
Oid tgreloid,
@@ -339,7 +337,7 @@ plpython_call_handler(PG_FUNCTION_ARGS)
HeapTuple trv;
proc = PLy_procedure_get(fcinfo,
- RelationGetRelid(tdata->tg_relation));
+ RelationGetRelid(tdata->tg_relation));
trv = PLy_trigger_handler(fcinfo, proc);
retval = PointerGetDatum(trv);
}
@@ -385,52 +383,52 @@ PLy_trigger_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
PG_TRY();
{
- plargs = PLy_trigger_build_args(fcinfo, proc, &rv);
- plrv = PLy_procedure_call(proc, "TD", plargs);
+ plargs = PLy_trigger_build_args(fcinfo, proc, &rv);
+ plrv = PLy_procedure_call(proc, "TD", plargs);
- Assert(plrv != NULL);
- Assert(!PLy_error_in_progress);
+ Assert(plrv != NULL);
+ Assert(!PLy_error_in_progress);
- /*
- * Disconnect from SPI manager
- */
- if (SPI_finish() != SPI_OK_FINISH)
- elog(ERROR, "SPI_finish failed");
+ /*
+ * Disconnect from SPI manager
+ */
+ if (SPI_finish() != SPI_OK_FINISH)
+ elog(ERROR, "SPI_finish failed");
- /*
- * return of None means we're happy with the tuple
- */
- if (plrv != Py_None)
- {
- char *srv;
+ /*
+ * return of None means we're happy with the tuple
+ */
+ if (plrv != Py_None)
+ {
+ char *srv;
- if (!PyString_Check(plrv))
- elog(ERROR, "expected trigger to return None or a String");
+ if (!PyString_Check(plrv))
+ elog(ERROR, "expected trigger to return None or a String");
- srv = PyString_AsString(plrv);
- if (pg_strcasecmp(srv, "SKIP") == 0)
- rv = NULL;
- else if (pg_strcasecmp(srv, "MODIFY") == 0)
- {
- TriggerData *tdata = (TriggerData *) fcinfo->context;
+ srv = PyString_AsString(plrv);
+ if (pg_strcasecmp(srv, "SKIP") == 0)
+ rv = NULL;
+ else if (pg_strcasecmp(srv, "MODIFY") == 0)
+ {
+ TriggerData *tdata = (TriggerData *) fcinfo->context;
- if ((TRIGGER_FIRED_BY_INSERT(tdata->tg_event)) ||
- (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event)))
- rv = PLy_modify_tuple(proc, plargs, tdata, rv);
- else
- elog(WARNING, "ignoring modified tuple in DELETE trigger");
- }
- else if (pg_strcasecmp(srv, "OK") != 0)
- {
- /*
- * hmmm, perhaps they only read the pltcl page, not a
- * surprising thing since i've written no documentation, so
- * accept a belated OK
- */
- elog(ERROR, "expected return to be \"SKIP\" or \"MODIFY\"");
+ if ((TRIGGER_FIRED_BY_INSERT(tdata->tg_event)) ||
+ (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event)))
+ rv = PLy_modify_tuple(proc, plargs, tdata, rv);
+ else
+ elog(WARNING, "ignoring modified tuple in DELETE trigger");
+ }
+ else if (pg_strcasecmp(srv, "OK") != 0)
+ {
+ /*
+ * hmmm, perhaps they only read the pltcl page, not a
+ * surprising thing since i've written no documentation,
+ * so accept a belated OK
+ */
+ elog(ERROR, "expected return to be \"SKIP\" or \"MODIFY\"");
+ }
}
}
- }
PG_CATCH();
{
Py_XDECREF(plargs);
@@ -472,70 +470,70 @@ PLy_modify_tuple(PLyProcedure * proc, PyObject * pltd, TriggerData *tdata,
PG_TRY();
{
- if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
- elog(ERROR, "TD[\"new\"] deleted, unable to modify tuple");
- if (!PyDict_Check(plntup))
- elog(ERROR, "TD[\"new\"] is not a dictionary object");
- Py_INCREF(plntup);
+ if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
+ elog(ERROR, "TD[\"new\"] deleted, unable to modify tuple");
+ if (!PyDict_Check(plntup))
+ elog(ERROR, "TD[\"new\"] is not a dictionary object");
+ Py_INCREF(plntup);
- plkeys = PyDict_Keys(plntup);
- natts = PyList_Size(plkeys);
+ plkeys = PyDict_Keys(plntup);
+ natts = PyList_Size(plkeys);
- modattrs = (int *) palloc(natts * sizeof(int));
- modvalues = (Datum *) palloc(natts * sizeof(Datum));
- modnulls = (char *) palloc(natts * sizeof(char));
+ modattrs = (int *) palloc(natts * sizeof(int));
+ modvalues = (Datum *) palloc(natts * sizeof(Datum));
+ modnulls = (char *) palloc(natts * sizeof(char));
- tupdesc = tdata->tg_relation->rd_att;
+ tupdesc = tdata->tg_relation->rd_att;
- for (i = 0; i < natts; i++)
- {
- char *src;
+ for (i = 0; i < natts; i++)
+ {
+ char *src;
- platt = PyList_GetItem(plkeys, i);
- if (!PyString_Check(platt))
- elog(ERROR, "attribute name is not a string");
- attn = SPI_fnumber(tupdesc, PyString_AsString(platt));
- if (attn == SPI_ERROR_NOATTRIBUTE)
- elog(ERROR, "invalid attribute \"%s\" in tuple",
- PyString_AsString(platt));
- atti = attn - 1;
+ platt = PyList_GetItem(plkeys, i);
+ if (!PyString_Check(platt))
+ elog(ERROR, "attribute name is not a string");
+ attn = SPI_fnumber(tupdesc, PyString_AsString(platt));
+ if (attn == SPI_ERROR_NOATTRIBUTE)
+ elog(ERROR, "invalid attribute \"%s\" in tuple",
+ PyString_AsString(platt));
+ atti = attn - 1;
- plval = PyDict_GetItem(plntup, platt);
- if (plval == NULL)
- elog(FATAL, "python interpreter is probably corrupted");
+ plval = PyDict_GetItem(plntup, platt);
+ if (plval == NULL)
+ elog(FATAL, "python interpreter is probably corrupted");
- Py_INCREF(plval);
+ Py_INCREF(plval);
- modattrs[i] = attn;
+ modattrs[i] = attn;
- if (plval != Py_None && !tupdesc->attrs[atti]->attisdropped)
- {
- plstr = PyObject_Str(plval);
- src = PyString_AsString(plstr);
+ if (plval != Py_None && !tupdesc->attrs[atti]->attisdropped)
+ {
+ plstr = PyObject_Str(plval);
+ src = PyString_AsString(plstr);
- modvalues[i] = FunctionCall3(&proc->result.out.r.atts[atti].typfunc,
- CStringGetDatum(src),
- ObjectIdGetDatum(proc->result.out.r.atts[atti].typioparam),
+ modvalues[i] = FunctionCall3(&proc->result.out.r.atts[atti].typfunc,
+ CStringGetDatum(src),
+ ObjectIdGetDatum(proc->result.out.r.atts[atti].typioparam),
Int32GetDatum(tupdesc->attrs[atti]->atttypmod));
- modnulls[i] = ' ';
+ modnulls[i] = ' ';
- Py_DECREF(plstr);
- plstr = NULL;
- }
- else
- {
- modvalues[i] = (Datum) 0;
- modnulls[i] = 'n';
- }
+ Py_DECREF(plstr);
+ plstr = NULL;
+ }
+ else
+ {
+ modvalues[i] = (Datum) 0;
+ modnulls[i] = 'n';
+ }
- Py_DECREF(plval);
- plval = NULL;
- }
+ Py_DECREF(plval);
+ plval = NULL;
+ }
- rtup = SPI_modifytuple(tdata->tg_relation, otup, natts,
- modattrs, modvalues, modnulls);
- if (rtup == NULL)
- elog(ERROR, "SPI_modifytuple failed -- error %d", SPI_result);
+ rtup = SPI_modifytuple(tdata->tg_relation, otup, natts,
+ modattrs, modvalues, modnulls);
+ if (rtup == NULL)
+ elog(ERROR, "SPI_modifytuple failed -- error %d", SPI_result);
}
PG_CATCH();
{
@@ -583,138 +581,138 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc, HeapTuple *
PG_TRY();
{
- pltdata = PyDict_New();
- if (!pltdata)
- PLy_elog(ERROR, "could not build arguments for trigger procedure");
+ pltdata = PyDict_New();
+ if (!pltdata)
+ PLy_elog(ERROR, "could not build arguments for trigger procedure");
- pltname = PyString_FromString(tdata->tg_trigger->tgname);
- PyDict_SetItemString(pltdata, "name", pltname);
- Py_DECREF(pltname);
+ pltname = PyString_FromString(tdata->tg_trigger->tgname);
+ PyDict_SetItemString(pltdata, "name", pltname);
+ Py_DECREF(pltname);
- stroid = DatumGetCString(DirectFunctionCall1(oidout,
+ stroid = DatumGetCString(DirectFunctionCall1(oidout,
ObjectIdGetDatum(tdata->tg_relation->rd_id)));
- pltrelid = PyString_FromString(stroid);
- PyDict_SetItemString(pltdata, "relid", pltrelid);
- Py_DECREF(pltrelid);
- pfree(stroid);
-
- if (TRIGGER_FIRED_BEFORE(tdata->tg_event))
- pltwhen = PyString_FromString("BEFORE");
- else if (TRIGGER_FIRED_AFTER(tdata->tg_event))
- pltwhen = PyString_FromString("AFTER");
- else
- {
- elog(ERROR, "unrecognized WHEN tg_event: %u", tdata->tg_event);
- pltwhen = NULL; /* keep compiler quiet */
- }
- PyDict_SetItemString(pltdata, "when", pltwhen);
- Py_DECREF(pltwhen);
-
- if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
- {
- pltlevel = PyString_FromString("ROW");
- PyDict_SetItemString(pltdata, "level", pltlevel);
- Py_DECREF(pltlevel);
+ pltrelid = PyString_FromString(stroid);
+ PyDict_SetItemString(pltdata, "relid", pltrelid);
+ Py_DECREF(pltrelid);
+ pfree(stroid);
+
+ if (TRIGGER_FIRED_BEFORE(tdata->tg_event))
+ pltwhen = PyString_FromString("BEFORE");
+ else if (TRIGGER_FIRED_AFTER(tdata->tg_event))
+ pltwhen = PyString_FromString("AFTER");
+ else
+ {
+ elog(ERROR, "unrecognized WHEN tg_event: %u", tdata->tg_event);
+ pltwhen = NULL; /* keep compiler quiet */
+ }
+ PyDict_SetItemString(pltdata, "when", pltwhen);
+ Py_DECREF(pltwhen);
- if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
+ if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
{
- pltevent = PyString_FromString("INSERT");
+ pltlevel = PyString_FromString("ROW");
+ PyDict_SetItemString(pltdata, "level", pltlevel);
+ Py_DECREF(pltlevel);
- PyDict_SetItemString(pltdata, "old", Py_None);
- pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
- tdata->tg_relation->rd_att);
- PyDict_SetItemString(pltdata, "new", pytnew);
- Py_DECREF(pytnew);
- *rv = tdata->tg_trigtuple;
+ if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
+ {
+ pltevent = PyString_FromString("INSERT");
+
+ PyDict_SetItemString(pltdata, "old", Py_None);
+ pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
+ tdata->tg_relation->rd_att);
+ PyDict_SetItemString(pltdata, "new", pytnew);
+ Py_DECREF(pytnew);
+ *rv = tdata->tg_trigtuple;
+ }
+ else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
+ {
+ pltevent = PyString_FromString("DELETE");
+
+ PyDict_SetItemString(pltdata, "new", Py_None);
+ pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
+ tdata->tg_relation->rd_att);
+ PyDict_SetItemString(pltdata, "old", pytold);
+ Py_DECREF(pytold);
+ *rv = tdata->tg_trigtuple;
+ }
+ else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
+ {
+ pltevent = PyString_FromString("UPDATE");
+
+ pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_newtuple,
+ tdata->tg_relation->rd_att);
+ PyDict_SetItemString(pltdata, "new", pytnew);
+ Py_DECREF(pytnew);
+ pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
+ tdata->tg_relation->rd_att);
+ PyDict_SetItemString(pltdata, "old", pytold);
+ Py_DECREF(pytold);
+ *rv = tdata->tg_newtuple;
+ }
+ else
+ {
+ elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
+ pltevent = NULL; /* keep compiler quiet */
+ }
+
+ PyDict_SetItemString(pltdata, "event", pltevent);
+ Py_DECREF(pltevent);
}
- else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
+ else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))
{
- pltevent = PyString_FromString("DELETE");
+ pltlevel = PyString_FromString("STATEMENT");
+ PyDict_SetItemString(pltdata, "level", pltlevel);
+ Py_DECREF(pltlevel);
+ PyDict_SetItemString(pltdata, "old", Py_None);
PyDict_SetItemString(pltdata, "new", Py_None);
- pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
- tdata->tg_relation->rd_att);
- PyDict_SetItemString(pltdata, "old", pytold);
- Py_DECREF(pytold);
- *rv = tdata->tg_trigtuple;
- }
- else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
- {
- pltevent = PyString_FromString("UPDATE");
-
- pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_newtuple,
- tdata->tg_relation->rd_att);
- PyDict_SetItemString(pltdata, "new", pytnew);
- Py_DECREF(pytnew);
- pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
- tdata->tg_relation->rd_att);
- PyDict_SetItemString(pltdata, "old", pytold);
- Py_DECREF(pytold);
- *rv = tdata->tg_newtuple;
+ *rv = NULL;
+
+ if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
+ pltevent = PyString_FromString("INSERT");
+ else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
+ pltevent = PyString_FromString("DELETE");
+ else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
+ pltevent = PyString_FromString("UPDATE");
+ else
+ {
+ elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
+ pltevent = NULL; /* keep compiler quiet */
+ }
+
+ PyDict_SetItemString(pltdata, "event", pltevent);
+ Py_DECREF(pltevent);
}
else
- {
- elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
- pltevent = NULL; /* keep compiler quiet */
- }
+ elog(ERROR, "unrecognized LEVEL tg_event: %u", tdata->tg_event);
- PyDict_SetItemString(pltdata, "event", pltevent);
- Py_DECREF(pltevent);
- }
- else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))
- {
- pltlevel = PyString_FromString("STATEMENT");
- PyDict_SetItemString(pltdata, "level", pltlevel);
- Py_DECREF(pltlevel);
-
- PyDict_SetItemString(pltdata, "old", Py_None);
- PyDict_SetItemString(pltdata, "new", Py_None);
- *rv = NULL;
-
- if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
- pltevent = PyString_FromString("INSERT");
- else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
- pltevent = PyString_FromString("DELETE");
- else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
- pltevent = PyString_FromString("UPDATE");
- else
+ if (tdata->tg_trigger->tgnargs)
{
- elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
- pltevent = NULL; /* keep compiler quiet */
- }
-
- PyDict_SetItemString(pltdata, "event", pltevent);
- Py_DECREF(pltevent);
- }
- else
- elog(ERROR, "unrecognized LEVEL tg_event: %u", tdata->tg_event);
+ /*
+ * all strings...
+ */
+ int i;
+ PyObject *pltarg;
- if (tdata->tg_trigger->tgnargs)
- {
- /*
- * all strings...
- */
- int i;
- PyObject *pltarg;
+ pltargs = PyList_New(tdata->tg_trigger->tgnargs);
+ for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
+ {
+ pltarg = PyString_FromString(tdata->tg_trigger->tgargs[i]);
- pltargs = PyList_New(tdata->tg_trigger->tgnargs);
- for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
+ /*
+ * stolen, don't Py_DECREF
+ */
+ PyList_SetItem(pltargs, i, pltarg);
+ }
+ }
+ else
{
- pltarg = PyString_FromString(tdata->tg_trigger->tgargs[i]);
-
- /*
- * stolen, don't Py_DECREF
- */
- PyList_SetItem(pltargs, i, pltarg);
+ Py_INCREF(Py_None);
+ pltargs = Py_None;
}
- }
- else
- {
- Py_INCREF(Py_None);
- pltargs = Py_None;
- }
- PyDict_SetItemString(pltdata, "args", pltargs);
- Py_DECREF(pltargs);
+ PyDict_SetItemString(pltdata, "args", pltargs);
+ Py_DECREF(pltargs);
}
PG_CATCH();
{
@@ -741,39 +739,39 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
PG_TRY();
{
- plargs = PLy_function_build_args(fcinfo, proc);
- plrv = PLy_procedure_call(proc, "args", plargs);
+ plargs = PLy_function_build_args(fcinfo, proc);
+ plrv = PLy_procedure_call(proc, "args", plargs);
- Assert(plrv != NULL);
- Assert(!PLy_error_in_progress);
+ Assert(plrv != NULL);
+ Assert(!PLy_error_in_progress);
- /*
- * Disconnect from SPI manager and then create the return values datum
- * (if the input function does a palloc for it this must not be
- * allocated in the SPI memory context because SPI_finish would free
- * it).
- */
- if (SPI_finish() != SPI_OK_FINISH)
- elog(ERROR, "SPI_finish failed");
+ /*
+ * Disconnect from SPI manager and then create the return values
+ * datum (if the input function does a palloc for it this must not
+ * be allocated in the SPI memory context because SPI_finish would
+ * free it).
+ */
+ if (SPI_finish() != SPI_OK_FINISH)
+ elog(ERROR, "SPI_finish failed");
- /*
- * convert the python PyObject to a postgresql Datum
- */
- if (plrv == Py_None)
- {
- fcinfo->isnull = true;
- rv = (Datum) NULL;
- }
- else
- {
- fcinfo->isnull = false;
- plrv_so = PyObject_Str(plrv);
- plrv_sc = PyString_AsString(plrv_so);
- rv = FunctionCall3(&proc->result.out.d.typfunc,
- PointerGetDatum(plrv_sc),
- ObjectIdGetDatum(proc->result.out.d.typioparam),
- Int32GetDatum(-1));
- }
+ /*
+ * convert the python PyObject to a postgresql Datum
+ */
+ if (plrv == Py_None)
+ {
+ fcinfo->isnull = true;
+ rv = (Datum) NULL;
+ }
+ else
+ {
+ fcinfo->isnull = false;
+ plrv_so = PyObject_Str(plrv);
+ plrv_sc = PyString_AsString(plrv_so);
+ rv = FunctionCall3(&proc->result.out.d.typfunc,
+ PointerGetDatum(plrv_sc),
+ ObjectIdGetDatum(proc->result.out.d.typioparam),
+ Int32GetDatum(-1));
+ }
}
PG_CATCH();
@@ -807,12 +805,12 @@ PLy_procedure_call(PLyProcedure * proc, char *kargs, PyObject * vargs)
PLy_last_procedure = current;
/*
- * If there was an error in a PG callback, propagate that
- * no matter what Python claims about its success.
+ * If there was an error in a PG callback, propagate that no matter
+ * what Python claims about its success.
*/
if (PLy_error_in_progress)
{
- ErrorData *edata = PLy_error_in_progress;
+ ErrorData *edata = PLy_error_in_progress;
PLy_error_in_progress = NULL;
ReThrowError(edata);
@@ -836,68 +834,68 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc)
PG_TRY();
{
- args = PyList_New(proc->nargs);
- for (i = 0; i < proc->nargs; i++)
- {
- if (proc->args[i].is_rowtype > 0)
+ args = PyList_New(proc->nargs);
+ for (i = 0; i < proc->nargs; i++)
{
- if (fcinfo->argnull[i])
- arg = NULL;
- else
+ if (proc->args[i].is_rowtype > 0)
{
- HeapTupleHeader td;
- Oid tupType;
- int32 tupTypmod;
- TupleDesc tupdesc;
- HeapTupleData tmptup;
-
- td = DatumGetHeapTupleHeader(fcinfo->arg[i]);
- /* Extract rowtype info and find a tupdesc */
- tupType = HeapTupleHeaderGetTypeId(td);
- tupTypmod = HeapTupleHeaderGetTypMod(td);
- tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
-
- /* Set up I/O funcs if not done yet */
- if (proc->args[i].is_rowtype != 1)
- PLy_input_tuple_funcs(&(proc->args[i]), tupdesc);
-
- /* Build a temporary HeapTuple control structure */
- tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
- tmptup.t_data = td;
-
- arg = PLyDict_FromTuple(&(proc->args[i]), &tmptup, tupdesc);
+ if (fcinfo->argnull[i])
+ arg = NULL;
+ else
+ {
+ HeapTupleHeader td;
+ Oid tupType;
+ int32 tupTypmod;
+ TupleDesc tupdesc;
+ HeapTupleData tmptup;
+
+ td = DatumGetHeapTupleHeader(fcinfo->arg[i]);
+ /* Extract rowtype info and find a tupdesc */
+ tupType = HeapTupleHeaderGetTypeId(td);
+ tupTypmod = HeapTupleHeaderGetTypMod(td);
+ tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
+
+ /* Set up I/O funcs if not done yet */
+ if (proc->args[i].is_rowtype != 1)
+ PLy_input_tuple_funcs(&(proc->args[i]), tupdesc);
+
+ /* Build a temporary HeapTuple control structure */
+ tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
+ tmptup.t_data = td;
+
+ arg = PLyDict_FromTuple(&(proc->args[i]), &tmptup, tupdesc);
+ }
}
- }
- else
- {
- if (fcinfo->argnull[i])
- arg = NULL;
else
{
- char *ct;
- Datum dt;
-
- dt = FunctionCall3(&(proc->args[i].in.d.typfunc),
- fcinfo->arg[i],
- ObjectIdGetDatum(proc->args[i].in.d.typioparam),
- Int32GetDatum(-1));
- ct = DatumGetCString(dt);
- arg = (proc->args[i].in.d.func) (ct);
- pfree(ct);
+ if (fcinfo->argnull[i])
+ arg = NULL;
+ else
+ {
+ char *ct;
+ Datum dt;
+
+ dt = FunctionCall3(&(proc->args[i].in.d.typfunc),
+ fcinfo->arg[i],
+ ObjectIdGetDatum(proc->args[i].in.d.typioparam),
+ Int32GetDatum(-1));
+ ct = DatumGetCString(dt);
+ arg = (proc->args[i].in.d.func) (ct);
+ pfree(ct);
+ }
}
- }
- if (arg == NULL)
- {
- Py_INCREF(Py_None);
- arg = Py_None;
- }
+ if (arg == NULL)
+ {
+ Py_INCREF(Py_None);
+ arg = Py_None;
+ }
- /*
- * FIXME -- error check this
- */
- PyList_SetItem(args, i, arg);
- }
+ /*
+ * FIXME -- error check this
+ */
+ PyList_SetItem(args, i, arg);
+ }
}
PG_CATCH();
{
@@ -917,7 +915,7 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc)
*/
/* PLy_procedure_get: returns a cached PLyProcedure, or creates, stores and
- * returns a new PLyProcedure. fcinfo is the call info, tgreloid is the
+ * returns a new PLyProcedure. fcinfo is the call info, tgreloid is the
* relation OID when calling a trigger, or InvalidOid (zero) for ordinary
* function calls.
*/
@@ -1016,89 +1014,90 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
PG_TRY();
{
- /*
- * get information required for output conversion of the return value,
- * but only if this isn't a trigger.
- */
- if (!CALLED_AS_TRIGGER(fcinfo))
- {
- HeapTuple rvTypeTup;
- Form_pg_type rvTypeStruct;
+ /*
+ * get information required for output conversion of the return
+ * value, but only if this isn't a trigger.
+ */
+ if (!CALLED_AS_TRIGGER(fcinfo))
+ {
+ HeapTuple rvTypeTup;
+ Form_pg_type rvTypeStruct;
- rvTypeTup = SearchSysCache(TYPEOID,
+ rvTypeTup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(procStruct->prorettype),
- 0, 0, 0);
- if (!HeapTupleIsValid(rvTypeTup))
- elog(ERROR, "cache lookup failed for type %u",
- procStruct->prorettype);
+ 0, 0, 0);
+ if (!HeapTupleIsValid(rvTypeTup))
+ elog(ERROR, "cache lookup failed for type %u",
+ procStruct->prorettype);
+
+ rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
+ if (rvTypeStruct->typtype != 'c')
+ PLy_output_datum_func(&proc->result, rvTypeTup);
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("tuple return types are not supported yet")));
- rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
- if (rvTypeStruct->typtype != 'c')
- PLy_output_datum_func(&proc->result, rvTypeTup);
+ ReleaseSysCache(rvTypeTup);
+ }
else
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("tuple return types are not supported yet")));
+ {
+ /*
+ * input/output conversion for trigger tuples. use the result
+ * TypeInfo variable to store the tuple conversion info.
+ */
+ TriggerData *tdata = (TriggerData *) fcinfo->context;
+
+ PLy_input_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);
+ PLy_output_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);
+ }
- ReleaseSysCache(rvTypeTup);
- }
- else
- {
/*
- * input/output conversion for trigger tuples. use the result
- * TypeInfo variable to store the tuple conversion info.
+ * now get information required for input conversion of the
+ * procedures arguments.
*/
- TriggerData *tdata = (TriggerData *) fcinfo->context;
-
- PLy_input_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);
- PLy_output_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);
- }
-
- /*
- * now get information required for input conversion of the procedures
- * arguments.
- */
- proc->nargs = fcinfo->nargs;
- for (i = 0; i < fcinfo->nargs; i++)
- {
- HeapTuple argTypeTup;
- Form_pg_type argTypeStruct;
+ proc->nargs = fcinfo->nargs;
+ for (i = 0; i < fcinfo->nargs; i++)
+ {
+ HeapTuple argTypeTup;
+ Form_pg_type argTypeStruct;
- argTypeTup = SearchSysCache(TYPEOID,
+ argTypeTup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(procStruct->proargtypes[i]),
- 0, 0, 0);
- if (!HeapTupleIsValid(argTypeTup))
- elog(ERROR, "cache lookup failed for type %u",
- procStruct->proargtypes[i]);
- argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
-
- if (argTypeStruct->typtype != 'c')
- PLy_input_datum_func(&(proc->args[i]),
- procStruct->proargtypes[i],
- argTypeTup);
- else
- proc->args[i].is_rowtype = 2; /* still need to set I/O funcs */
+ 0, 0, 0);
+ if (!HeapTupleIsValid(argTypeTup))
+ elog(ERROR, "cache lookup failed for type %u",
+ procStruct->proargtypes[i]);
+ argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
+
+ if (argTypeStruct->typtype != 'c')
+ PLy_input_datum_func(&(proc->args[i]),
+ procStruct->proargtypes[i],
+ argTypeTup);
+ else
+ proc->args[i].is_rowtype = 2; /* still need to set I/O
+ * funcs */
- ReleaseSysCache(argTypeTup);
- }
+ ReleaseSysCache(argTypeTup);
+ }
- /*
- * get the text of the function.
- */
- prosrcdatum = SysCacheGetAttr(PROCOID, procTup,
- Anum_pg_proc_prosrc, &isnull);
- if (isnull)
- elog(ERROR, "null prosrc");
- procSource = DatumGetCString(DirectFunctionCall1(textout,
- prosrcdatum));
+ /*
+ * get the text of the function.
+ */
+ prosrcdatum = SysCacheGetAttr(PROCOID, procTup,
+ Anum_pg_proc_prosrc, &isnull);
+ if (isnull)
+ elog(ERROR, "null prosrc");
+ procSource = DatumGetCString(DirectFunctionCall1(textout,
+ prosrcdatum));
- PLy_procedure_compile(proc, procSource);
+ PLy_procedure_compile(proc, procSource);
- pfree(procSource);
+ pfree(procSource);
- proc->me = PyCObject_FromVoidPtr(proc, NULL);
- PyDict_SetItemString(PLy_procedure_cache, key, proc->me);
+ proc->me = PyCObject_FromVoidPtr(proc, NULL);
+ PyDict_SetItemString(PLy_procedure_cache, key, proc->me);
}
PG_CATCH();
{
@@ -1437,41 +1436,41 @@ PLyDict_FromTuple(PLyTypeInfo * info, HeapTuple tuple, TupleDesc desc)
PG_TRY();
{
- for (i = 0; i < info->in.r.natts; i++)
- {
- char *key,
- *vsrc;
- Datum vattr,
- vdat;
- bool is_null;
- PyObject *value;
+ for (i = 0; i < info->in.r.natts; i++)
+ {
+ char *key,
+ *vsrc;
+ Datum vattr,
+ vdat;
+ bool is_null;
+ PyObject *value;
- if (desc->attrs[i]->attisdropped)
- continue;
+ if (desc->attrs[i]->attisdropped)
+ continue;
- key = NameStr(desc->attrs[i]->attname);
- vattr = heap_getattr(tuple, (i + 1), desc, &is_null);
+ key = NameStr(desc->attrs[i]->attname);
+ vattr = heap_getattr(tuple, (i + 1), desc, &is_null);
- if ((is_null) || (info->in.r.atts[i].func == NULL))
- PyDict_SetItemString(dict, key, Py_None);
- else
- {
- vdat = FunctionCall3(&info->in.r.atts[i].typfunc,
- vattr,
- ObjectIdGetDatum(info->in.r.atts[i].typioparam),
+ if ((is_null) || (info->in.r.atts[i].func == NULL))
+ PyDict_SetItemString(dict, key, Py_None);
+ else
+ {
+ vdat = FunctionCall3(&info->in.r.atts[i].typfunc,
+ vattr,
+ ObjectIdGetDatum(info->in.r.atts[i].typioparam),
Int32GetDatum(desc->attrs[i]->atttypmod));
- vsrc = DatumGetCString(vdat);
-
- /*
- * no exceptions allowed
- */
- value = info->in.r.atts[i].func(vsrc);
- pfree(vsrc);
- PyDict_SetItemString(dict, key, value);
- Py_DECREF(value);
+ vsrc = DatumGetCString(vdat);
+
+ /*
+ * no exceptions allowed
+ */
+ value = info->in.r.atts[i].func(vsrc);
+ pfree(vsrc);
+ PyDict_SetItemString(dict, key, value);
+ Py_DECREF(value);
+ }
}
}
- }
PG_CATCH();
{
Py_DECREF(dict);
@@ -1858,68 +1857,72 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
oldcontext = CurrentMemoryContext;
PG_TRY();
{
- if (list != NULL)
- {
- int nargs,
- i;
-
- nargs = PySequence_Length(list);
- if (nargs > 0)
+ if (list != NULL)
{
- plan->nargs = nargs;
- plan->types = PLy_malloc(sizeof(Oid) * nargs);
- plan->values = PLy_malloc(sizeof(Datum) * nargs);
- plan->args = PLy_malloc(sizeof(PLyTypeInfo) * nargs);
+ int nargs,
+ i;
- /*
- * the other loop might throw an exception, if PLyTypeInfo
- * member isn't properly initialized the Py_DECREF(plan) will
- * go boom
- */
- for (i = 0; i < nargs; i++)
+ nargs = PySequence_Length(list);
+ if (nargs > 0)
{
- PLy_typeinfo_init(&plan->args[i]);
- plan->values[i] = (Datum) NULL;
- }
+ plan->nargs = nargs;
+ plan->types = PLy_malloc(sizeof(Oid) * nargs);
+ plan->values = PLy_malloc(sizeof(Datum) * nargs);
+ plan->args = PLy_malloc(sizeof(PLyTypeInfo) * nargs);
+
+ /*
+ * the other loop might throw an exception, if PLyTypeInfo
+ * member isn't properly initialized the Py_DECREF(plan)
+ * will go boom
+ */
+ for (i = 0; i < nargs; i++)
+ {
+ PLy_typeinfo_init(&plan->args[i]);
+ plan->values[i] = (Datum) NULL;
+ }
- for (i = 0; i < nargs; i++)
- {
- char *sptr;
- HeapTuple typeTup;
- Form_pg_type typeStruct;
-
- optr = PySequence_GetItem(list, i);
- if (!PyString_Check(optr))
- elog(ERROR, "Type names must be strings.");
- sptr = PyString_AsString(optr);
- /* XXX should extend this to allow qualified type names */
- typeTup = typenameType(makeTypeName(sptr));
- Py_DECREF(optr);
- optr = NULL; /* this is important */
-
- plan->types[i] = HeapTupleGetOid(typeTup);
- typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
- if (typeStruct->typtype != 'c')
- PLy_output_datum_func(&plan->args[i], typeTup);
- else
- elog(ERROR, "tuples not handled in plpy.prepare, yet.");
- ReleaseSysCache(typeTup);
+ for (i = 0; i < nargs; i++)
+ {
+ char *sptr;
+ HeapTuple typeTup;
+ Form_pg_type typeStruct;
+
+ optr = PySequence_GetItem(list, i);
+ if (!PyString_Check(optr))
+ elog(ERROR, "Type names must be strings.");
+ sptr = PyString_AsString(optr);
+
+ /*
+ * XXX should extend this to allow qualified type
+ * names
+ */
+ typeTup = typenameType(makeTypeName(sptr));
+ Py_DECREF(optr);
+ optr = NULL; /* this is important */
+
+ plan->types[i] = HeapTupleGetOid(typeTup);
+ typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
+ if (typeStruct->typtype != 'c')
+ PLy_output_datum_func(&plan->args[i], typeTup);
+ else
+ elog(ERROR, "tuples not handled in plpy.prepare, yet.");
+ ReleaseSysCache(typeTup);
+ }
}
}
- }
- plan->plan = SPI_prepare(query, plan->nargs, plan->types);
- if (plan->plan == NULL)
- elog(ERROR, "SPI_prepare failed: %s",
- SPI_result_code_string(SPI_result));
-
- /* transfer plan from procCxt to topCxt */
- tmpplan = plan->plan;
- plan->plan = SPI_saveplan(tmpplan);
- SPI_freeplan(tmpplan);
- if (plan->plan == NULL)
- elog(ERROR, "SPI_saveplan failed: %s",
- SPI_result_code_string(SPI_result));
+ plan->plan = SPI_prepare(query, plan->nargs, plan->types);
+ if (plan->plan == NULL)
+ elog(ERROR, "SPI_prepare failed: %s",
+ SPI_result_code_string(SPI_result));
+
+ /* transfer plan from procCxt to topCxt */
+ tmpplan = plan->plan;
+ plan->plan = SPI_saveplan(tmpplan);
+ SPI_freeplan(tmpplan);
+ if (plan->plan == NULL)
+ elog(ERROR, "SPI_saveplan failed: %s",
+ SPI_result_code_string(SPI_result));
}
PG_CATCH();
{
@@ -2015,51 +2018,52 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, int limit)
oldcontext = CurrentMemoryContext;
PG_TRY();
{
- nulls = palloc(nargs * sizeof(char));
-
- for (i = 0; i < nargs; i++)
- {
- PyObject *elem,
- *so;
- char *sv;
+ nulls = palloc(nargs * sizeof(char));
- elem = PySequence_GetItem(list, i);
- if (elem != Py_None)
+ for (i = 0; i < nargs; i++)
{
- so = PyObject_Str(elem);
- sv = PyString_AsString(so);
-
- /*
- * FIXME -- if this elogs, we have Python reference leak
- */
- plan->values[i] =
- FunctionCall3(&(plan->args[i].out.d.typfunc),
- CStringGetDatum(sv),
- ObjectIdGetDatum(plan->args[i].out.d.typioparam),
- Int32GetDatum(-1));
+ PyObject *elem,
+ *so;
+ char *sv;
- Py_DECREF(so);
- Py_DECREF(elem);
-
- nulls[i] = ' ';
- }
- else
- {
- Py_DECREF(elem);
- plan->values[i] = (Datum) 0;
- nulls[i] = 'n';
+ elem = PySequence_GetItem(list, i);
+ if (elem != Py_None)
+ {
+ so = PyObject_Str(elem);
+ sv = PyString_AsString(so);
+
+ /*
+ * FIXME -- if this elogs, we have Python reference leak
+ */
+ plan->values[i] =
+ FunctionCall3(&(plan->args[i].out.d.typfunc),
+ CStringGetDatum(sv),
+ ObjectIdGetDatum(plan->args[i].out.d.typioparam),
+ Int32GetDatum(-1));
+
+ Py_DECREF(so);
+ Py_DECREF(elem);
+
+ nulls[i] = ' ';
+ }
+ else
+ {
+ Py_DECREF(elem);
+ plan->values[i] = (Datum) 0;
+ nulls[i] = 'n';
+ }
}
- }
- rv = SPI_execp(plan->plan, plan->values, nulls, limit);
+ rv = SPI_execp(plan->plan, plan->values, nulls, limit);
- pfree(nulls);
+ pfree(nulls);
}
PG_CATCH();
{
MemoryContextSwitchTo(oldcontext);
PLy_error_in_progress = CopyErrorData();
FlushErrorState();
+
/*
* cleanup plan->values array
*/
@@ -2110,9 +2114,7 @@ PLy_spi_execute_query(char *query, int limit)
oldcontext = CurrentMemoryContext;
PG_TRY();
- {
rv = SPI_exec(query, limit);
- }
PG_CATCH();
{
MemoryContextSwitchTo(oldcontext);
@@ -2178,7 +2180,7 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
for (i = 0; i < rows; i++)
{
PyObject *row = PLyDict_FromTuple(&args, tuptable->vals[i],
- tuptable->tupdesc);
+ tuptable->tupdesc);
PyList_SetItem(result->rows, i, row);
}
@@ -2194,7 +2196,7 @@ PLy_spi_execute_fetch_result(SPITupleTable *tuptable, int rows, int status)
FlushErrorState();
if (!PyErr_Occurred())
PyErr_SetString(PLy_exc_error,
- "Unknown error in PLy_spi_execute_fetch_result");
+ "Unknown error in PLy_spi_execute_fetch_result");
Py_DECREF(result);
PLy_typeinfo_dealloc(&args);
return NULL;
@@ -2373,15 +2375,14 @@ PLy_output(volatile int level, PyObject * self, PyObject * args)
oldcontext = CurrentMemoryContext;
PG_TRY();
- {
elog(level, "%s", sv);
- }
PG_CATCH();
{
MemoryContextSwitchTo(oldcontext);
PLy_error_in_progress = CopyErrorData();
FlushErrorState();
Py_XDECREF(so);
+
/*
* returning NULL here causes the python interpreter to bail. when
* control passes back to PLy_procedure_call, we check for PG