Header And Logo

PostgreSQL
| The world's most advanced open source database.

plpy_exec.c

Go to the documentation of this file.
00001 /*
00002  * executing Python code
00003  *
00004  * src/pl/plpython/plpy_exec.c
00005  */
00006 
00007 #include "postgres.h"
00008 
00009 #include "access/htup_details.h"
00010 #include "access/xact.h"
00011 #include "catalog/pg_type.h"
00012 #include "commands/trigger.h"
00013 #include "executor/spi.h"
00014 #include "funcapi.h"
00015 #include "utils/builtins.h"
00016 #include "utils/rel.h"
00017 #include "utils/typcache.h"
00018 
00019 #include "plpython.h"
00020 
00021 #include "plpy_exec.h"
00022 
00023 #include "plpy_elog.h"
00024 #include "plpy_main.h"
00025 #include "plpy_procedure.h"
00026 #include "plpy_subxactobject.h"
00027 
00028 
00029 static PyObject *PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc);
00030 static void PLy_function_delete_args(PLyProcedure *proc);
00031 static void plpython_return_error_callback(void *arg);
00032 
00033 static PyObject *PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc,
00034                        HeapTuple *rv);
00035 static HeapTuple PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd,
00036                  TriggerData *tdata, HeapTuple otup);
00037 static void plpython_trigger_error_callback(void *arg);
00038 
00039 static PyObject *PLy_procedure_call(PLyProcedure *proc, char *kargs, PyObject *vargs);
00040 static void PLy_abort_open_subtransactions(int save_subxact_level);
00041 
00042 
00043 /* function subhandler */
00044 Datum
00045 PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc)
00046 {
00047     Datum       rv;
00048     PyObject   *volatile plargs = NULL;
00049     PyObject   *volatile plrv = NULL;
00050     ErrorContextCallback plerrcontext;
00051 
00052     PG_TRY();
00053     {
00054         if (!proc->is_setof || proc->setof == NULL)
00055         {
00056             /*
00057              * Simple type returning function or first time for SETOF
00058              * function: actually execute the function.
00059              */
00060             plargs = PLy_function_build_args(fcinfo, proc);
00061             plrv = PLy_procedure_call(proc, "args", plargs);
00062             if (!proc->is_setof)
00063             {
00064                 /*
00065                  * SETOF function parameters will be deleted when last row is
00066                  * returned
00067                  */
00068                 PLy_function_delete_args(proc);
00069             }
00070             Assert(plrv != NULL);
00071         }
00072 
00073         /*
00074          * If it returns a set, call the iterator to get the next return item.
00075          * We stay in the SPI context while doing this, because PyIter_Next()
00076          * calls back into Python code which might contain SPI calls.
00077          */
00078         if (proc->is_setof)
00079         {
00080             bool        has_error = false;
00081             ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
00082 
00083             if (proc->setof == NULL)
00084             {
00085                 /* first time -- do checks and setup */
00086                 if (!rsi || !IsA(rsi, ReturnSetInfo) ||
00087                     (rsi->allowedModes & SFRM_ValuePerCall) == 0)
00088                 {
00089                     ereport(ERROR,
00090                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00091                              errmsg("unsupported set function return mode"),
00092                              errdetail("PL/Python set-returning functions only support returning only value per call.")));
00093                 }
00094                 rsi->returnMode = SFRM_ValuePerCall;
00095 
00096                 /* Make iterator out of returned object */
00097                 proc->setof = PyObject_GetIter(plrv);
00098                 Py_DECREF(plrv);
00099                 plrv = NULL;
00100 
00101                 if (proc->setof == NULL)
00102                     ereport(ERROR,
00103                             (errcode(ERRCODE_DATATYPE_MISMATCH),
00104                              errmsg("returned object cannot be iterated"),
00105                              errdetail("PL/Python set-returning functions must return an iterable object.")));
00106             }
00107 
00108             /* Fetch next from iterator */
00109             plrv = PyIter_Next(proc->setof);
00110             if (plrv)
00111                 rsi->isDone = ExprMultipleResult;
00112             else
00113             {
00114                 rsi->isDone = ExprEndResult;
00115                 has_error = PyErr_Occurred() != NULL;
00116             }
00117 
00118             if (rsi->isDone == ExprEndResult)
00119             {
00120                 /* Iterator is exhausted or error happened */
00121                 Py_DECREF(proc->setof);
00122                 proc->setof = NULL;
00123 
00124                 Py_XDECREF(plargs);
00125                 Py_XDECREF(plrv);
00126 
00127                 PLy_function_delete_args(proc);
00128 
00129                 if (has_error)
00130                     PLy_elog(ERROR, "error fetching next item from iterator");
00131 
00132                 /* Disconnect from the SPI manager before returning */
00133                 if (SPI_finish() != SPI_OK_FINISH)
00134                     elog(ERROR, "SPI_finish failed");
00135 
00136                 fcinfo->isnull = true;
00137                 return (Datum) NULL;
00138             }
00139         }
00140 
00141         /*
00142          * Disconnect from SPI manager and then create the return values datum
00143          * (if the input function does a palloc for it this must not be
00144          * allocated in the SPI memory context because SPI_finish would free
00145          * it).
00146          */
00147         if (SPI_finish() != SPI_OK_FINISH)
00148             elog(ERROR, "SPI_finish failed");
00149 
00150         plerrcontext.callback = plpython_return_error_callback;
00151         plerrcontext.previous = error_context_stack;
00152         error_context_stack = &plerrcontext;
00153 
00154         /*
00155          * If the function is declared to return void, the Python return value
00156          * must be None. For void-returning functions, we also treat a None
00157          * return value as a special "void datum" rather than NULL (as is the
00158          * case for non-void-returning functions).
00159          */
00160         if (proc->result.out.d.typoid == VOIDOID)
00161         {
00162             if (plrv != Py_None)
00163                 ereport(ERROR,
00164                         (errcode(ERRCODE_DATATYPE_MISMATCH),
00165                          errmsg("PL/Python function with return type \"void\" did not return None")));
00166 
00167             fcinfo->isnull = false;
00168             rv = (Datum) 0;
00169         }
00170         else if (plrv == Py_None)
00171         {
00172             fcinfo->isnull = true;
00173             if (proc->result.is_rowtype < 1)
00174                 rv = InputFunctionCall(&proc->result.out.d.typfunc,
00175                                        NULL,
00176                                        proc->result.out.d.typioparam,
00177                                        -1);
00178             else
00179                 /* Tuple as None */
00180                 rv = (Datum) NULL;
00181         }
00182         else if (proc->result.is_rowtype >= 1)
00183         {
00184             TupleDesc   desc;
00185 
00186             /* make sure it's not an unnamed record */
00187             Assert((proc->result.out.d.typoid == RECORDOID &&
00188                     proc->result.out.d.typmod != -1) ||
00189                    (proc->result.out.d.typoid != RECORDOID &&
00190                     proc->result.out.d.typmod == -1));
00191 
00192             desc = lookup_rowtype_tupdesc(proc->result.out.d.typoid,
00193                                           proc->result.out.d.typmod);
00194 
00195             rv = PLyObject_ToCompositeDatum(&proc->result, desc, plrv);
00196             fcinfo->isnull = (rv == (Datum) NULL);
00197         }
00198         else
00199         {
00200             fcinfo->isnull = false;
00201             rv = (proc->result.out.d.func) (&proc->result.out.d, -1, plrv);
00202         }
00203     }
00204     PG_CATCH();
00205     {
00206         Py_XDECREF(plargs);
00207         Py_XDECREF(plrv);
00208 
00209         /*
00210          * If there was an error the iterator might have not been exhausted
00211          * yet. Set it to NULL so the next invocation of the function will
00212          * start the iteration again.
00213          */
00214         Py_XDECREF(proc->setof);
00215         proc->setof = NULL;
00216 
00217         PG_RE_THROW();
00218     }
00219     PG_END_TRY();
00220 
00221     error_context_stack = plerrcontext.previous;
00222 
00223     Py_XDECREF(plargs);
00224     Py_DECREF(plrv);
00225 
00226     return rv;
00227 }
00228 
00229 /* trigger subhandler
00230  *
00231  * the python function is expected to return Py_None if the tuple is
00232  * acceptable and unmodified.  Otherwise it should return a PyString
00233  * object who's value is SKIP, or MODIFY.  SKIP means don't perform
00234  * this action.  MODIFY means the tuple has been modified, so update
00235  * tuple and perform action.  SKIP and MODIFY assume the trigger fires
00236  * BEFORE the event and is ROW level.  postgres expects the function
00237  * to take no arguments and return an argument of type trigger.
00238  */
00239 HeapTuple
00240 PLy_exec_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
00241 {
00242     HeapTuple   rv = NULL;
00243     PyObject   *volatile plargs = NULL;
00244     PyObject   *volatile plrv = NULL;
00245     TriggerData *tdata;
00246 
00247     Assert(CALLED_AS_TRIGGER(fcinfo));
00248 
00249     /*
00250      * Input/output conversion for trigger tuples.  Use the result TypeInfo
00251      * variable to store the tuple conversion info.  We do this over again on
00252      * each call to cover the possibility that the relation's tupdesc changed
00253      * since the trigger was last called. PLy_input_tuple_funcs and
00254      * PLy_output_tuple_funcs are responsible for not doing repetitive work.
00255      */
00256     tdata = (TriggerData *) fcinfo->context;
00257 
00258     PLy_input_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);
00259     PLy_output_tuple_funcs(&(proc->result), tdata->tg_relation->rd_att);
00260 
00261     PG_TRY();
00262     {
00263         plargs = PLy_trigger_build_args(fcinfo, proc, &rv);
00264         plrv = PLy_procedure_call(proc, "TD", plargs);
00265 
00266         Assert(plrv != NULL);
00267 
00268         /*
00269          * Disconnect from SPI manager
00270          */
00271         if (SPI_finish() != SPI_OK_FINISH)
00272             elog(ERROR, "SPI_finish failed");
00273 
00274         /*
00275          * return of None means we're happy with the tuple
00276          */
00277         if (plrv != Py_None)
00278         {
00279             char       *srv;
00280 
00281             if (PyString_Check(plrv))
00282                 srv = PyString_AsString(plrv);
00283             else if (PyUnicode_Check(plrv))
00284                 srv = PLyUnicode_AsString(plrv);
00285             else
00286             {
00287                 ereport(ERROR,
00288                         (errcode(ERRCODE_DATA_EXCEPTION),
00289                     errmsg("unexpected return value from trigger procedure"),
00290                          errdetail("Expected None or a string.")));
00291                 srv = NULL;     /* keep compiler quiet */
00292             }
00293 
00294             if (pg_strcasecmp(srv, "SKIP") == 0)
00295                 rv = NULL;
00296             else if (pg_strcasecmp(srv, "MODIFY") == 0)
00297             {
00298                 TriggerData *tdata = (TriggerData *) fcinfo->context;
00299 
00300                 if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event) ||
00301                     TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
00302                     rv = PLy_modify_tuple(proc, plargs, tdata, rv);
00303                 else
00304                     ereport(WARNING,
00305                             (errmsg("PL/Python trigger function returned \"MODIFY\" in a DELETE trigger -- ignored")));
00306             }
00307             else if (pg_strcasecmp(srv, "OK") != 0)
00308             {
00309                 /*
00310                  * accept "OK" as an alternative to None; otherwise, raise an
00311                  * error
00312                  */
00313                 ereport(ERROR,
00314                         (errcode(ERRCODE_DATA_EXCEPTION),
00315                     errmsg("unexpected return value from trigger procedure"),
00316                          errdetail("Expected None, \"OK\", \"SKIP\", or \"MODIFY\".")));
00317             }
00318         }
00319     }
00320     PG_CATCH();
00321     {
00322         Py_XDECREF(plargs);
00323         Py_XDECREF(plrv);
00324 
00325         PG_RE_THROW();
00326     }
00327     PG_END_TRY();
00328 
00329     Py_DECREF(plargs);
00330     Py_DECREF(plrv);
00331 
00332     return rv;
00333 }
00334 
00335 /* helper functions for Python code execution */
00336 
00337 static PyObject *
00338 PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
00339 {
00340     PyObject   *volatile arg = NULL;
00341     PyObject   *volatile args = NULL;
00342     int         i;
00343 
00344     PG_TRY();
00345     {
00346         args = PyList_New(proc->nargs);
00347         for (i = 0; i < proc->nargs; i++)
00348         {
00349             if (proc->args[i].is_rowtype > 0)
00350             {
00351                 if (fcinfo->argnull[i])
00352                     arg = NULL;
00353                 else
00354                 {
00355                     HeapTupleHeader td;
00356                     Oid         tupType;
00357                     int32       tupTypmod;
00358                     TupleDesc   tupdesc;
00359                     HeapTupleData tmptup;
00360 
00361                     td = DatumGetHeapTupleHeader(fcinfo->arg[i]);
00362                     /* Extract rowtype info and find a tupdesc */
00363                     tupType = HeapTupleHeaderGetTypeId(td);
00364                     tupTypmod = HeapTupleHeaderGetTypMod(td);
00365                     tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
00366 
00367                     /* Set up I/O funcs if not done yet */
00368                     if (proc->args[i].is_rowtype != 1)
00369                         PLy_input_tuple_funcs(&(proc->args[i]), tupdesc);
00370 
00371                     /* Build a temporary HeapTuple control structure */
00372                     tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
00373                     tmptup.t_data = td;
00374 
00375                     arg = PLyDict_FromTuple(&(proc->args[i]), &tmptup, tupdesc);
00376                     ReleaseTupleDesc(tupdesc);
00377                 }
00378             }
00379             else
00380             {
00381                 if (fcinfo->argnull[i])
00382                     arg = NULL;
00383                 else
00384                 {
00385                     arg = (proc->args[i].in.d.func) (&(proc->args[i].in.d),
00386                                                      fcinfo->arg[i]);
00387                 }
00388             }
00389 
00390             if (arg == NULL)
00391             {
00392                 Py_INCREF(Py_None);
00393                 arg = Py_None;
00394             }
00395 
00396             if (PyList_SetItem(args, i, arg) == -1)
00397                 PLy_elog(ERROR, "PyList_SetItem() failed, while setting up arguments");
00398 
00399             if (proc->argnames && proc->argnames[i] &&
00400             PyDict_SetItemString(proc->globals, proc->argnames[i], arg) == -1)
00401                 PLy_elog(ERROR, "PyDict_SetItemString() failed, while setting up arguments");
00402             arg = NULL;
00403         }
00404 
00405         /* Set up output conversion for functions returning RECORD */
00406         if (proc->result.out.d.typoid == RECORDOID)
00407         {
00408             TupleDesc   desc;
00409 
00410             if (get_call_result_type(fcinfo, NULL, &desc) != TYPEFUNC_COMPOSITE)
00411                 ereport(ERROR,
00412                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00413                          errmsg("function returning record called in context "
00414                                 "that cannot accept type record")));
00415 
00416             /* cache the output conversion functions */
00417             PLy_output_record_funcs(&(proc->result), desc);
00418         }
00419     }
00420     PG_CATCH();
00421     {
00422         Py_XDECREF(arg);
00423         Py_XDECREF(args);
00424 
00425         PG_RE_THROW();
00426     }
00427     PG_END_TRY();
00428 
00429     return args;
00430 }
00431 
00432 static void
00433 PLy_function_delete_args(PLyProcedure *proc)
00434 {
00435     int         i;
00436 
00437     if (!proc->argnames)
00438         return;
00439 
00440     for (i = 0; i < proc->nargs; i++)
00441         if (proc->argnames[i])
00442             PyDict_DelItemString(proc->globals, proc->argnames[i]);
00443 }
00444 
00445 static void
00446 plpython_return_error_callback(void *arg)
00447 {
00448     PLyExecutionContext *exec_ctx = PLy_current_execution_context();
00449 
00450     if (exec_ctx->curr_proc)
00451         errcontext("while creating return value");
00452 }
00453 
00454 static PyObject *
00455 PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *rv)
00456 {
00457     TriggerData *tdata = (TriggerData *) fcinfo->context;
00458     PyObject   *pltname,
00459                *pltevent,
00460                *pltwhen,
00461                *pltlevel,
00462                *pltrelid,
00463                *plttablename,
00464                *plttableschema;
00465     PyObject   *pltargs,
00466                *pytnew,
00467                *pytold;
00468     PyObject   *volatile pltdata = NULL;
00469     char       *stroid;
00470 
00471     PG_TRY();
00472     {
00473         pltdata = PyDict_New();
00474         if (!pltdata)
00475             PLy_elog(ERROR, "could not create new dictionary while building trigger arguments");
00476 
00477         pltname = PyString_FromString(tdata->tg_trigger->tgname);
00478         PyDict_SetItemString(pltdata, "name", pltname);
00479         Py_DECREF(pltname);
00480 
00481         stroid = DatumGetCString(DirectFunctionCall1(oidout,
00482                                ObjectIdGetDatum(tdata->tg_relation->rd_id)));
00483         pltrelid = PyString_FromString(stroid);
00484         PyDict_SetItemString(pltdata, "relid", pltrelid);
00485         Py_DECREF(pltrelid);
00486         pfree(stroid);
00487 
00488         stroid = SPI_getrelname(tdata->tg_relation);
00489         plttablename = PyString_FromString(stroid);
00490         PyDict_SetItemString(pltdata, "table_name", plttablename);
00491         Py_DECREF(plttablename);
00492         pfree(stroid);
00493 
00494         stroid = SPI_getnspname(tdata->tg_relation);
00495         plttableschema = PyString_FromString(stroid);
00496         PyDict_SetItemString(pltdata, "table_schema", plttableschema);
00497         Py_DECREF(plttableschema);
00498         pfree(stroid);
00499 
00500         if (TRIGGER_FIRED_BEFORE(tdata->tg_event))
00501             pltwhen = PyString_FromString("BEFORE");
00502         else if (TRIGGER_FIRED_AFTER(tdata->tg_event))
00503             pltwhen = PyString_FromString("AFTER");
00504         else if (TRIGGER_FIRED_INSTEAD(tdata->tg_event))
00505             pltwhen = PyString_FromString("INSTEAD OF");
00506         else
00507         {
00508             elog(ERROR, "unrecognized WHEN tg_event: %u", tdata->tg_event);
00509             pltwhen = NULL;     /* keep compiler quiet */
00510         }
00511         PyDict_SetItemString(pltdata, "when", pltwhen);
00512         Py_DECREF(pltwhen);
00513 
00514         if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
00515         {
00516             pltlevel = PyString_FromString("ROW");
00517             PyDict_SetItemString(pltdata, "level", pltlevel);
00518             Py_DECREF(pltlevel);
00519 
00520             if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
00521             {
00522                 pltevent = PyString_FromString("INSERT");
00523 
00524                 PyDict_SetItemString(pltdata, "old", Py_None);
00525                 pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
00526                                            tdata->tg_relation->rd_att);
00527                 PyDict_SetItemString(pltdata, "new", pytnew);
00528                 Py_DECREF(pytnew);
00529                 *rv = tdata->tg_trigtuple;
00530             }
00531             else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
00532             {
00533                 pltevent = PyString_FromString("DELETE");
00534 
00535                 PyDict_SetItemString(pltdata, "new", Py_None);
00536                 pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
00537                                            tdata->tg_relation->rd_att);
00538                 PyDict_SetItemString(pltdata, "old", pytold);
00539                 Py_DECREF(pytold);
00540                 *rv = tdata->tg_trigtuple;
00541             }
00542             else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
00543             {
00544                 pltevent = PyString_FromString("UPDATE");
00545 
00546                 pytnew = PLyDict_FromTuple(&(proc->result), tdata->tg_newtuple,
00547                                            tdata->tg_relation->rd_att);
00548                 PyDict_SetItemString(pltdata, "new", pytnew);
00549                 Py_DECREF(pytnew);
00550                 pytold = PLyDict_FromTuple(&(proc->result), tdata->tg_trigtuple,
00551                                            tdata->tg_relation->rd_att);
00552                 PyDict_SetItemString(pltdata, "old", pytold);
00553                 Py_DECREF(pytold);
00554                 *rv = tdata->tg_newtuple;
00555             }
00556             else
00557             {
00558                 elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
00559                 pltevent = NULL;    /* keep compiler quiet */
00560             }
00561 
00562             PyDict_SetItemString(pltdata, "event", pltevent);
00563             Py_DECREF(pltevent);
00564         }
00565         else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))
00566         {
00567             pltlevel = PyString_FromString("STATEMENT");
00568             PyDict_SetItemString(pltdata, "level", pltlevel);
00569             Py_DECREF(pltlevel);
00570 
00571             PyDict_SetItemString(pltdata, "old", Py_None);
00572             PyDict_SetItemString(pltdata, "new", Py_None);
00573             *rv = NULL;
00574 
00575             if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
00576                 pltevent = PyString_FromString("INSERT");
00577             else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
00578                 pltevent = PyString_FromString("DELETE");
00579             else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
00580                 pltevent = PyString_FromString("UPDATE");
00581             else if (TRIGGER_FIRED_BY_TRUNCATE(tdata->tg_event))
00582                 pltevent = PyString_FromString("TRUNCATE");
00583             else
00584             {
00585                 elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
00586                 pltevent = NULL;    /* keep compiler quiet */
00587             }
00588 
00589             PyDict_SetItemString(pltdata, "event", pltevent);
00590             Py_DECREF(pltevent);
00591         }
00592         else
00593             elog(ERROR, "unrecognized LEVEL tg_event: %u", tdata->tg_event);
00594 
00595         if (tdata->tg_trigger->tgnargs)
00596         {
00597             /*
00598              * all strings...
00599              */
00600             int         i;
00601             PyObject   *pltarg;
00602 
00603             pltargs = PyList_New(tdata->tg_trigger->tgnargs);
00604             for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
00605             {
00606                 pltarg = PyString_FromString(tdata->tg_trigger->tgargs[i]);
00607 
00608                 /*
00609                  * stolen, don't Py_DECREF
00610                  */
00611                 PyList_SetItem(pltargs, i, pltarg);
00612             }
00613         }
00614         else
00615         {
00616             Py_INCREF(Py_None);
00617             pltargs = Py_None;
00618         }
00619         PyDict_SetItemString(pltdata, "args", pltargs);
00620         Py_DECREF(pltargs);
00621     }
00622     PG_CATCH();
00623     {
00624         Py_XDECREF(pltdata);
00625         PG_RE_THROW();
00626     }
00627     PG_END_TRY();
00628 
00629     return pltdata;
00630 }
00631 
00632 static HeapTuple
00633 PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
00634                  HeapTuple otup)
00635 {
00636     PyObject   *volatile plntup;
00637     PyObject   *volatile plkeys;
00638     PyObject   *volatile platt;
00639     PyObject   *volatile plval;
00640     PyObject   *volatile plstr;
00641     HeapTuple   rtup;
00642     int         natts,
00643                 i,
00644                 attn,
00645                 atti;
00646     int        *volatile modattrs;
00647     Datum      *volatile modvalues;
00648     char       *volatile modnulls;
00649     TupleDesc   tupdesc;
00650     ErrorContextCallback plerrcontext;
00651 
00652     plerrcontext.callback = plpython_trigger_error_callback;
00653     plerrcontext.previous = error_context_stack;
00654     error_context_stack = &plerrcontext;
00655 
00656     plntup = plkeys = platt = plval = plstr = NULL;
00657     modattrs = NULL;
00658     modvalues = NULL;
00659     modnulls = NULL;
00660 
00661     PG_TRY();
00662     {
00663         if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
00664             ereport(ERROR,
00665                     (errmsg("TD[\"new\"] deleted, cannot modify row")));
00666         if (!PyDict_Check(plntup))
00667             ereport(ERROR,
00668                     (errmsg("TD[\"new\"] is not a dictionary")));
00669         Py_INCREF(plntup);
00670 
00671         plkeys = PyDict_Keys(plntup);
00672         natts = PyList_Size(plkeys);
00673 
00674         modattrs = (int *) palloc(natts * sizeof(int));
00675         modvalues = (Datum *) palloc(natts * sizeof(Datum));
00676         modnulls = (char *) palloc(natts * sizeof(char));
00677 
00678         tupdesc = tdata->tg_relation->rd_att;
00679 
00680         for (i = 0; i < natts; i++)
00681         {
00682             char       *plattstr;
00683 
00684             platt = PyList_GetItem(plkeys, i);
00685             if (PyString_Check(platt))
00686                 plattstr = PyString_AsString(platt);
00687             else if (PyUnicode_Check(platt))
00688                 plattstr = PLyUnicode_AsString(platt);
00689             else
00690             {
00691                 ereport(ERROR,
00692                         (errmsg("TD[\"new\"] dictionary key at ordinal position %d is not a string", i)));
00693                 plattstr = NULL;    /* keep compiler quiet */
00694             }
00695             attn = SPI_fnumber(tupdesc, plattstr);
00696             if (attn == SPI_ERROR_NOATTRIBUTE)
00697                 ereport(ERROR,
00698                         (errmsg("key \"%s\" found in TD[\"new\"] does not exist as a column in the triggering row",
00699                                 plattstr)));
00700             atti = attn - 1;
00701 
00702             plval = PyDict_GetItem(plntup, platt);
00703             if (plval == NULL)
00704                 elog(FATAL, "Python interpreter is probably corrupted");
00705 
00706             Py_INCREF(plval);
00707 
00708             modattrs[i] = attn;
00709 
00710             if (tupdesc->attrs[atti]->attisdropped)
00711             {
00712                 modvalues[i] = (Datum) 0;
00713                 modnulls[i] = 'n';
00714             }
00715             else if (plval != Py_None)
00716             {
00717                 PLyObToDatum *att = &proc->result.out.r.atts[atti];
00718 
00719                 modvalues[i] = (att->func) (att,
00720                                             tupdesc->attrs[atti]->atttypmod,
00721                                             plval);
00722                 modnulls[i] = ' ';
00723             }
00724             else
00725             {
00726                 modvalues[i] =
00727                     InputFunctionCall(&proc->result.out.r.atts[atti].typfunc,
00728                                       NULL,
00729                                     proc->result.out.r.atts[atti].typioparam,
00730                                       tupdesc->attrs[atti]->atttypmod);
00731                 modnulls[i] = 'n';
00732             }
00733 
00734             Py_DECREF(plval);
00735             plval = NULL;
00736         }
00737 
00738         rtup = SPI_modifytuple(tdata->tg_relation, otup, natts,
00739                                modattrs, modvalues, modnulls);
00740         if (rtup == NULL)
00741             elog(ERROR, "SPI_modifytuple failed: error %d", SPI_result);
00742     }
00743     PG_CATCH();
00744     {
00745         Py_XDECREF(plntup);
00746         Py_XDECREF(plkeys);
00747         Py_XDECREF(plval);
00748         Py_XDECREF(plstr);
00749 
00750         if (modnulls)
00751             pfree(modnulls);
00752         if (modvalues)
00753             pfree(modvalues);
00754         if (modattrs)
00755             pfree(modattrs);
00756 
00757         PG_RE_THROW();
00758     }
00759     PG_END_TRY();
00760 
00761     Py_DECREF(plntup);
00762     Py_DECREF(plkeys);
00763 
00764     pfree(modattrs);
00765     pfree(modvalues);
00766     pfree(modnulls);
00767 
00768     error_context_stack = plerrcontext.previous;
00769 
00770     return rtup;
00771 }
00772 
00773 static void
00774 plpython_trigger_error_callback(void *arg)
00775 {
00776     PLyExecutionContext *exec_ctx = PLy_current_execution_context();
00777 
00778     if (exec_ctx->curr_proc)
00779         errcontext("while modifying trigger row");
00780 }
00781 
00782 /* execute Python code, propagate Python errors to the backend */
00783 static PyObject *
00784 PLy_procedure_call(PLyProcedure *proc, char *kargs, PyObject *vargs)
00785 {
00786     PyObject   *rv;
00787     int volatile save_subxact_level = list_length(explicit_subtransactions);
00788 
00789     PyDict_SetItemString(proc->globals, kargs, vargs);
00790 
00791     PG_TRY();
00792     {
00793 #if PY_VERSION_HEX >= 0x03020000
00794         rv = PyEval_EvalCode(proc->code,
00795                              proc->globals, proc->globals);
00796 #else
00797         rv = PyEval_EvalCode((PyCodeObject *) proc->code,
00798                              proc->globals, proc->globals);
00799 #endif
00800 
00801         /*
00802          * Since plpy will only let you close subtransactions that you
00803          * started, you cannot *unnest* subtransactions, only *nest* them
00804          * without closing.
00805          */
00806         Assert(list_length(explicit_subtransactions) >= save_subxact_level);
00807     }
00808     PG_CATCH();
00809     {
00810         PLy_abort_open_subtransactions(save_subxact_level);
00811         PG_RE_THROW();
00812     }
00813     PG_END_TRY();
00814 
00815     PLy_abort_open_subtransactions(save_subxact_level);
00816 
00817     /* If the Python code returned an error, propagate it */
00818     if (rv == NULL)
00819         PLy_elog(ERROR, NULL);
00820 
00821     return rv;
00822 }
00823 
00824 /*
00825  * Abort lingering subtransactions that have been explicitly started
00826  * by plpy.subtransaction().start() and not properly closed.
00827  */
00828 static void
00829 PLy_abort_open_subtransactions(int save_subxact_level)
00830 {
00831     Assert(save_subxact_level >= 0);
00832 
00833     while (list_length(explicit_subtransactions) > save_subxact_level)
00834     {
00835         PLySubtransactionData *subtransactiondata;
00836 
00837         Assert(explicit_subtransactions != NIL);
00838 
00839         ereport(WARNING,
00840                 (errmsg("forcibly aborting a subtransaction that has not been exited")));
00841 
00842         RollbackAndReleaseCurrentSubTransaction();
00843 
00844         SPI_restore_connection();
00845 
00846         subtransactiondata = (PLySubtransactionData *) linitial(explicit_subtransactions);
00847         explicit_subtransactions = list_delete_first(explicit_subtransactions);
00848 
00849         MemoryContextSwitchTo(subtransactiondata->oldcontext);
00850         CurrentResourceOwner = subtransactiondata->oldowner;
00851         PLy_free(subtransactiondata);
00852     }
00853 }