diff options
Diffstat (limited to 'src/pl/plpython/plpy_exec.c')
-rw-r--r-- | src/pl/plpython/plpy_exec.c | 173 |
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); |