summaryrefslogtreecommitdiff
path: root/src/pl/plpython/plpy_exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pl/plpython/plpy_exec.c')
-rw-r--r--src/pl/plpython/plpy_exec.c173
1 files changed, 59 insertions, 114 deletions
diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c
index 26f61dd0f37..02d7d2ad5f8 100644
--- a/src/pl/plpython/plpy_exec.c
+++ b/src/pl/plpython/plpy_exec.c
@@ -202,7 +202,7 @@ PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc)
* return value as a special "void datum" rather than NULL (as is the
* case for non-void-returning functions).
*/
- if (proc->result.out.d.typoid == VOIDOID)
+ if (proc->result.typoid == VOIDOID)
{
if (plrv != Py_None)
ereport(ERROR,
@@ -212,48 +212,22 @@ PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc)
fcinfo->isnull = false;
rv = (Datum) 0;
}
- else if (plrv == Py_None)
+ else if (plrv == Py_None &&
+ srfstate && srfstate->iter == NULL)
{
- fcinfo->isnull = true;
-
/*
* In a SETOF function, the iteration-ending null isn't a real
* value; don't pass it through the input function, which might
* complain.
*/
- if (srfstate && srfstate->iter == NULL)
- rv = (Datum) 0;
- else if (proc->result.is_rowtype < 1)
- rv = InputFunctionCall(&proc->result.out.d.typfunc,
- NULL,
- proc->result.out.d.typioparam,
- -1);
- else
- /* Tuple as None */
- rv = (Datum) NULL;
- }
- else if (proc->result.is_rowtype >= 1)
- {
- TupleDesc desc;
-
- /* make sure it's not an unnamed record */
- Assert((proc->result.out.d.typoid == RECORDOID &&
- proc->result.out.d.typmod != -1) ||
- (proc->result.out.d.typoid != RECORDOID &&
- proc->result.out.d.typmod == -1));
-
- desc = lookup_rowtype_tupdesc(proc->result.out.d.typoid,
- proc->result.out.d.typmod);
-
- rv = PLyObject_ToCompositeDatum(&proc->result, desc, plrv, false);
- fcinfo->isnull = (rv == (Datum) NULL);
-
- ReleaseTupleDesc(desc);
+ fcinfo->isnull = true;
+ rv = (Datum) 0;
}
else
{
- fcinfo->isnull = false;
- rv = (proc->result.out.d.func) (&proc->result.out.d, -1, plrv, false);
+ /* Normal conversion of result */
+ rv = PLy_output_convert(&proc->result, plrv,
+ &fcinfo->isnull);
}
}
PG_CATCH();
@@ -328,20 +302,32 @@ PLy_exec_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
PyObject *volatile plargs = NULL;
PyObject *volatile plrv = NULL;
TriggerData *tdata;
+ TupleDesc rel_descr;
Assert(CALLED_AS_TRIGGER(fcinfo));
+ tdata = (TriggerData *) fcinfo->context;
/*
- * Input/output conversion for trigger tuples. Use the result TypeInfo
- * variable to store the tuple conversion info. We do this over again on
- * each call to cover the possibility that the relation's tupdesc changed
- * since the trigger was last called. PLy_input_tuple_funcs and
- * PLy_output_tuple_funcs are responsible for not doing repetitive work.
+ * Input/output conversion for trigger tuples. We use the result and
+ * result_in fields to store the tuple conversion info. We do this over
+ * again on each call to cover the possibility that the relation's tupdesc
+ * changed since the trigger was last called. The PLy_xxx_setup_func
+ * calls should only happen once, but PLy_input_setup_tuple and
+ * PLy_output_setup_tuple are responsible for not doing repetitive work.
*/
- 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);
+ rel_descr = RelationGetDescr(tdata->tg_relation);
+ if (proc->result.typoid != rel_descr->tdtypeid)
+ PLy_output_setup_func(&proc->result, proc->mcxt,
+ rel_descr->tdtypeid,
+ rel_descr->tdtypmod,
+ proc);
+ if (proc->result_in.typoid != rel_descr->tdtypeid)
+ PLy_input_setup_func(&proc->result_in, proc->mcxt,
+ rel_descr->tdtypeid,
+ rel_descr->tdtypmod,
+ proc);
+ PLy_output_setup_tuple(&proc->result, rel_descr, proc);
+ PLy_input_setup_tuple(&proc->result_in, rel_descr, proc);
PG_TRY();
{
@@ -436,46 +422,12 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
args = PyList_New(proc->nargs);
for (i = 0; i < proc->nargs; i++)
{
- if (proc->args[i].is_rowtype > 0)
- {
- 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);
- ReleaseTupleDesc(tupdesc);
- }
- }
+ PLyDatumToOb *arginfo = &proc->args[i];
+
+ if (fcinfo->argnull[i])
+ arg = NULL;
else
- {
- if (fcinfo->argnull[i])
- arg = NULL;
- else
- {
- arg = (proc->args[i].in.d.func) (&(proc->args[i].in.d),
- fcinfo->arg[i]);
- }
- }
+ arg = PLy_input_convert(arginfo, fcinfo->arg[i]);
if (arg == NULL)
{
@@ -493,7 +445,7 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
}
/* Set up output conversion for functions returning RECORD */
- if (proc->result.out.d.typoid == RECORDOID)
+ if (proc->result.typoid == RECORDOID)
{
TupleDesc desc;
@@ -504,7 +456,7 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
"that cannot accept type record")));
/* cache the output conversion functions */
- PLy_output_record_funcs(&(proc->result), desc);
+ PLy_output_setup_record(&proc->result, desc, proc);
}
}
PG_CATCH();
@@ -723,6 +675,7 @@ static PyObject *
PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *rv)
{
TriggerData *tdata = (TriggerData *) fcinfo->context;
+ TupleDesc rel_descr = RelationGetDescr(tdata->tg_relation);
PyObject *pltname,
*pltevent,
*pltwhen,
@@ -790,8 +743,9 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
pltevent = PyString_FromString("INSERT");
PyDict_SetItemString(pltdata, "old", Py_None);
- pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
- tdata->tg_relation->rd_att);
+ pytnew = PLy_input_from_tuple(&proc->result_in,
+ tdata->tg_trigtuple,
+ rel_descr);
PyDict_SetItemString(pltdata, "new", pytnew);
Py_DECREF(pytnew);
*rv = tdata->tg_trigtuple;
@@ -801,8 +755,9 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
pltevent = PyString_FromString("DELETE");
PyDict_SetItemString(pltdata, "new", Py_None);
- pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
- tdata->tg_relation->rd_att);
+ pytold = PLy_input_from_tuple(&proc->result_in,
+ tdata->tg_trigtuple,
+ rel_descr);
PyDict_SetItemString(pltdata, "old", pytold);
Py_DECREF(pytold);
*rv = tdata->tg_trigtuple;
@@ -811,12 +766,14 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
{
pltevent = PyString_FromString("UPDATE");
- pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_newtuple,
- tdata->tg_relation->rd_att);
+ pytnew = PLy_input_from_tuple(&proc->result_in,
+ tdata->tg_newtuple,
+ rel_descr);
PyDict_SetItemString(pltdata, "new", pytnew);
Py_DECREF(pytnew);
- pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
- tdata->tg_relation->rd_att);
+ pytold = PLy_input_from_tuple(&proc->result_in,
+ tdata->tg_trigtuple,
+ rel_descr);
PyDict_SetItemString(pltdata, "old", pytold);
Py_DECREF(pytold);
*rv = tdata->tg_newtuple;
@@ -897,6 +854,9 @@ PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *r
return pltdata;
}
+/*
+ * Apply changes requested by a MODIFY return from a trigger function.
+ */
static HeapTuple
PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
HeapTuple otup)
@@ -938,7 +898,7 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
plkeys = PyDict_Keys(plntup);
nkeys = PyList_Size(plkeys);
- tupdesc = tdata->tg_relation->rd_att;
+ tupdesc = RelationGetDescr(tdata->tg_relation);
modvalues = (Datum *) palloc0(tupdesc->natts * sizeof(Datum));
modnulls = (bool *) palloc0(tupdesc->natts * sizeof(bool));
@@ -950,7 +910,6 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
char *plattstr;
int attn;
PLyObToDatum *att;
- Form_pg_attribute attr;
platt = PyList_GetItem(plkeys, i);
if (PyString_Check(platt))
@@ -975,7 +934,6 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot set system attribute \"%s\"",
plattstr)));
- att = &proc->result.out.r.atts[attn - 1];
plval = PyDict_GetItem(plntup, platt);
if (plval == NULL)
@@ -983,25 +941,12 @@ PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
Py_INCREF(plval);
- attr = TupleDescAttr(tupdesc, attn - 1);
- if (plval != Py_None)
- {
- modvalues[attn - 1] =
- (att->func) (att,
- attr->atttypmod,
- plval,
- false);
- modnulls[attn - 1] = false;
- }
- else
- {
- modvalues[attn - 1] =
- InputFunctionCall(&att->typfunc,
- NULL,
- att->typioparam,
- attr->atttypmod);
- modnulls[attn - 1] = true;
- }
+ /* We assume proc->result is set up to convert tuples properly */
+ att = &proc->result.u.tuple.atts[attn - 1];
+
+ modvalues[attn - 1] = PLy_output_convert(att,
+ plval,
+ &modnulls[attn - 1]);
modrepls[attn - 1] = true;
Py_DECREF(plval);