LCOV - code coverage report
Current view: top level - src/pl/plpython - plpy_exec.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19beta1 Lines: 93.3 % 420 392
Test Date: 2026-06-24 17:16:41 Functions: 100.0 % 17 17
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * executing Python code
       3              :  *
       4              :  * src/pl/plpython/plpy_exec.c
       5              :  */
       6              : 
       7              : #include "postgres.h"
       8              : 
       9              : #include "commands/event_trigger.h"
      10              : #include "commands/trigger.h"
      11              : #include "executor/spi.h"
      12              : #include "funcapi.h"
      13              : #include "plpy_elog.h"
      14              : #include "plpy_exec.h"
      15              : #include "plpy_main.h"
      16              : #include "plpy_subxactobject.h"
      17              : #include "plpy_util.h"
      18              : #include "utils/fmgrprotos.h"
      19              : 
      20              : static void ShutdownPLyFunction(Datum arg);
      21              : static PyObject *PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc);
      22              : static PLySavedArgs *PLy_function_save_args(PLyProcedure *proc);
      23              : static void PLy_function_restore_args(PLyProcedure *proc, PLySavedArgs *savedargs);
      24              : static void PLy_function_drop_args(PLySavedArgs *savedargs);
      25              : static void PLy_global_args_push(PLyProcedure *proc);
      26              : static void PLy_global_args_pop(PLyProcedure *proc);
      27              : static void plpython_return_error_callback(void *arg);
      28              : 
      29              : static PyObject *PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc,
      30              :                                         HeapTuple *rv);
      31              : static HeapTuple PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd,
      32              :                                   TriggerData *tdata, HeapTuple otup);
      33              : static void plpython_trigger_error_callback(void *arg);
      34              : 
      35              : static PyObject *PLy_procedure_call(PLyProcedure *proc, const char *kargs, PyObject *vargs);
      36              : static void PLy_abort_open_subtransactions(int save_subxact_level);
      37              : 
      38              : 
      39              : /* function subhandler */
      40              : Datum
      41          673 : PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedureCache *pcache)
      42              : {
      43          673 :     PLyProcedure *proc = pcache->proc;
      44          673 :     bool        is_setof = proc->is_setof;
      45          673 :     ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
      46              :     Datum       rv;
      47          673 :     PyObject   *volatile plargs = NULL;
      48          673 :     PyObject   *volatile plrv = NULL;
      49          673 :     PLySRFState *volatile srfstate = NULL;
      50              :     ErrorContextCallback plerrcontext;
      51              : 
      52              :     /*
      53              :      * If the function is called recursively, we must push outer-level
      54              :      * arguments into the stack.  This must be immediately before the PG_TRY
      55              :      * to ensure that the corresponding pop happens.
      56              :      */
      57          673 :     PLy_global_args_push(proc);
      58              : 
      59          673 :     PG_TRY();
      60              :     {
      61          673 :         if (is_setof)
      62              :         {
      63              :             /*
      64              :              * PL/Python returns sets in ValuePerCall mode, so the handler is
      65              :              * invoked once per result row.  Across those calls we keep the
      66              :              * iterator and saved arguments in the per-call-site cache
      67              :              * (pcache->srfstate); a NULL srfstate means this is the first
      68              :              * call of a new iteration, so we must set up that state now.
      69              :              */
      70          213 :             if (pcache->srfstate == NULL)
      71              :             {
      72           57 :                 if (!rsi || !IsA(rsi, ReturnSetInfo) ||
      73           57 :                     (rsi->allowedModes & SFRM_ValuePerCall) == 0)
      74              :                 {
      75            0 :                     ereport(ERROR,
      76              :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
      77              :                              errmsg("unsupported set function return mode"),
      78              :                              errdetail("PL/Python set-returning functions only support returning one value per call.")));
      79              :                 }
      80           57 :                 rsi->returnMode = SFRM_ValuePerCall;
      81              : 
      82           57 :                 pcache->srfstate = (PLySRFState *)
      83           57 :                     MemoryContextAllocZero(pcache->fcontext, sizeof(PLySRFState));
      84              : 
      85              :                 /*
      86              :                  * Register a shutdown callback so that the iterator state is
      87              :                  * released if execution is abandoned before the iterator is
      88              :                  * exhausted.  We'll unregister it again on normal completion.
      89              :                  */
      90           57 :                 RegisterExprContextCallback(rsi->econtext,
      91              :                                             ShutdownPLyFunction,
      92              :                                             PointerGetDatum(pcache));
      93           57 :                 pcache->shutdown_reg = true;
      94              :             }
      95              : 
      96          213 :             srfstate = pcache->srfstate;
      97              :         }
      98              : 
      99          673 :         if (srfstate == NULL || srfstate->iter == NULL)
     100              :         {
     101              :             /*
     102              :              * Non-SETOF function or first time for SETOF function: build
     103              :              * args, then actually execute the function.
     104              :              */
     105          517 :             plargs = PLy_function_build_args(fcinfo, proc);
     106          517 :             plrv = PLy_procedure_call(proc, "args", plargs);
     107          463 :             Assert(plrv != NULL);
     108              :         }
     109              :         else
     110              :         {
     111              :             /*
     112              :              * Second or later call for a SETOF function: restore arguments in
     113              :              * globals dict to what they were when we left off.  We must do
     114              :              * this in case multiple evaluations of the same SETOF function
     115              :              * are interleaved.  It's a bit annoying, since the iterator may
     116              :              * not look at the arguments at all, but we have no way to know
     117              :              * that.  Fortunately this isn't terribly expensive.
     118              :              */
     119          156 :             if (srfstate->savedargs)
     120          156 :                 PLy_function_restore_args(proc, srfstate->savedargs);
     121          156 :             srfstate->savedargs = NULL; /* deleted by restore_args */
     122              :         }
     123              : 
     124              :         /*
     125              :          * If it returns a set, call the iterator to get the next return item.
     126              :          * We stay in the SPI context while doing this, because PyIter_Next()
     127              :          * calls back into Python code which might contain SPI calls.
     128              :          */
     129          619 :         if (is_setof)
     130              :         {
     131          212 :             if (srfstate->iter == NULL)
     132              :             {
     133              :                 /* First time -- make iterator out of returned object */
     134           56 :                 srfstate->iter = PyObject_GetIter(plrv);
     135              : 
     136           56 :                 Py_DECREF(plrv);
     137           56 :                 plrv = NULL;
     138              : 
     139           56 :                 if (srfstate->iter == NULL)
     140            1 :                     ereport(ERROR,
     141              :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
     142              :                              errmsg("returned object cannot be iterated"),
     143              :                              errdetail("PL/Python set-returning functions must return an iterable object.")));
     144              :             }
     145              : 
     146              :             /* Fetch next from iterator */
     147          211 :             plrv = PyIter_Next(srfstate->iter);
     148          211 :             if (plrv == NULL)
     149              :             {
     150              :                 /* Iterator is exhausted or error happened */
     151           52 :                 bool        has_error = (PyErr_Occurred() != NULL);
     152              : 
     153           52 :                 Py_DECREF(srfstate->iter);
     154           52 :                 srfstate->iter = NULL;
     155              : 
     156           52 :                 if (has_error)
     157            1 :                     PLy_elog(ERROR, "error fetching next item from iterator");
     158              : 
     159              :                 /* Pass a null through the data-returning steps below */
     160              :                 Py_INCREF(Py_None);
     161           51 :                 plrv = Py_None;
     162              :             }
     163              :             else
     164              :             {
     165              :                 /*
     166              :                  * This won't be last call, so save argument values.  We do
     167              :                  * this again each time in case the iterator is changing those
     168              :                  * values.
     169              :                  */
     170          159 :                 srfstate->savedargs = PLy_function_save_args(proc);
     171              :             }
     172              :         }
     173              : 
     174              :         /*
     175              :          * Disconnect from SPI manager and then create the return values datum
     176              :          * (if the input function does a palloc for it this must not be
     177              :          * allocated in the SPI memory context because SPI_finish would free
     178              :          * it).
     179              :          */
     180          617 :         if (SPI_finish() != SPI_OK_FINISH)
     181            0 :             elog(ERROR, "SPI_finish failed");
     182              : 
     183          617 :         plerrcontext.callback = plpython_return_error_callback;
     184          617 :         plerrcontext.previous = error_context_stack;
     185          617 :         error_context_stack = &plerrcontext;
     186              : 
     187              :         /*
     188              :          * For a procedure or function declared to return void, the Python
     189              :          * return value must be None. For void-returning functions, we also
     190              :          * treat a None return value as a special "void datum" rather than
     191              :          * NULL (as is the case for non-void-returning functions).
     192              :          */
     193          617 :         if (proc->result.typoid == VOIDOID)
     194              :         {
     195           29 :             if (plrv != Py_None)
     196              :             {
     197            2 :                 if (proc->is_procedure)
     198            1 :                     ereport(ERROR,
     199              :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
     200              :                              errmsg("PL/Python procedure did not return None")));
     201              :                 else
     202            1 :                     ereport(ERROR,
     203              :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
     204              :                              errmsg("PL/Python function with return type \"void\" did not return None")));
     205              :             }
     206              : 
     207           27 :             fcinfo->isnull = false;
     208           27 :             rv = (Datum) 0;
     209              :         }
     210          588 :         else if (plrv == Py_None &&
     211           58 :                  srfstate && srfstate->iter == NULL)
     212              :         {
     213              :             /*
     214              :              * In a SETOF function, the iteration-ending null isn't a real
     215              :              * value; don't pass it through the input function, which might
     216              :              * complain.
     217              :              */
     218           51 :             fcinfo->isnull = true;
     219           51 :             rv = (Datum) 0;
     220              :         }
     221              :         else
     222              :         {
     223              :             /*
     224              :              * Normal conversion of result.  However, if the result is of type
     225              :              * RECORD, we have to set up for that each time through, since it
     226              :              * might be different from last time.
     227              :              */
     228          537 :             if (proc->result.typoid == RECORDOID)
     229              :             {
     230              :                 TupleDesc   desc;
     231              : 
     232          140 :                 if (get_call_result_type(fcinfo, NULL, &desc) != TYPEFUNC_COMPOSITE)
     233            0 :                     ereport(ERROR,
     234              :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     235              :                              errmsg("function returning record called in context "
     236              :                                     "that cannot accept type record")));
     237          140 :                 PLy_output_setup_record(&proc->result, desc, proc);
     238              :             }
     239              : 
     240          537 :             rv = PLy_output_convert(&proc->result, plrv,
     241              :                                     &fcinfo->isnull);
     242              :         }
     243              :     }
     244           92 :     PG_CATCH();
     245              :     {
     246              :         /* Pop old arguments from the stack if they were pushed above */
     247           92 :         PLy_global_args_pop(proc);
     248              : 
     249           92 :         Py_XDECREF(plargs);
     250           92 :         Py_XDECREF(plrv);
     251              : 
     252              :         /*
     253              :          * If we are erroring out of a SRF, clean up its state immediately.
     254              :          * ShutdownPLyFunction will not be called on abort, and the
     255              :          * memory-context callback only fires when the FmgrInfo's context is
     256              :          * torn down.  Releasing the Python references promptly avoids leaking
     257              :          * them if teardown is delayed, and clearing pcache->srfstate ensures
     258              :          * that if we reuse the pcache we won't mistake this for an iteration
     259              :          * still in progress.
     260              :          */
     261           92 :         PLy_function_cleanup_srfstate(pcache);
     262              : 
     263           92 :         PG_RE_THROW();
     264              :     }
     265          581 :     PG_END_TRY();
     266              : 
     267          581 :     error_context_stack = plerrcontext.previous;
     268              : 
     269              :     /* Pop old arguments from the stack if they were pushed above */
     270          581 :     PLy_global_args_pop(proc);
     271              : 
     272          581 :     Py_XDECREF(plargs);
     273          581 :     Py_DECREF(plrv);
     274              : 
     275          581 :     if (srfstate)
     276              :     {
     277              :         /* We're in a SRF, signal done-or-not via rsi->isDone */
     278          208 :         if (srfstate->iter == NULL)
     279              :         {
     280              :             /*
     281              :              * Iterator exhausted.  Unregister the shutdown callback since
     282              :              * we're done normally, then clean up srfstate.  (srfstate->iter
     283              :              * is already NULL here, so the cleanup just frees the struct.)
     284              :              */
     285           51 :             if (pcache->shutdown_reg)
     286              :             {
     287           51 :                 UnregisterExprContextCallback(rsi->econtext,
     288              :                                               ShutdownPLyFunction,
     289              :                                               PointerGetDatum(pcache));
     290           51 :                 pcache->shutdown_reg = false;
     291              :             }
     292           51 :             PLy_function_cleanup_srfstate(pcache);
     293              : 
     294           51 :             rsi->isDone = ExprEndResult;
     295           51 :             fcinfo->isnull = true;
     296           51 :             return (Datum) 0;
     297              :         }
     298              :         else
     299              :         {
     300          157 :             rsi->isDone = ExprMultipleResult;
     301          157 :             return rv;
     302              :         }
     303              :     }
     304              : 
     305              :     /* Plain function, just return the Datum value (possibly null) */
     306          373 :     return rv;
     307              : }
     308              : 
     309              : /*
     310              :  * ExprContext shutdown callback, invoked when the expression context that
     311              :  * ran a SRF is rescanned or freed at end of query.  This handles in-query
     312              :  * cancellation, e.g. a LIMIT that stops fetching before the iterator is
     313              :  * exhausted, or a rescan of the owning plan node.
     314              :  *
     315              :  * NB: this is not called during an error abort (see comments for
     316              :  * PLy_function_cleanup_srfstate).
     317              :  */
     318              : static void
     319            1 : ShutdownPLyFunction(Datum arg)
     320              : {
     321            1 :     PLyProcedureCache *pcache = (PLyProcedureCache *) DatumGetPointer(arg);
     322              : 
     323              :     /* execUtils.c will deregister the callback after we return */
     324            1 :     pcache->shutdown_reg = false;
     325              : 
     326            1 :     PLy_function_cleanup_srfstate(pcache);
     327            1 : }
     328              : 
     329              : /*
     330              :  * Release the Python references held by an in-progress set-returning
     331              :  * function, and free the SRF state.  This is a no-op if there is no active
     332              :  * SRF state, so it's safe to call more than once.
     333              :  *
     334              :  * The Python iterator and the saved argument values own reference counts on
     335              :  * Python objects, which are not released by transaction abort the way SQL
     336              :  * resources are.  We must therefore make sure this runs in every exit path.
     337              :  * There are four ways for a set-returning function to terminate:
     338              :  * 1. Normal completion of the iterator.  Then this is called from
     339              :  *    PLy_exec_function's normal exit path.
     340              :  * 2. Error thrown from within execution of the SRF.  Then this is called
     341              :  *    from PLy_exec_function's PG_CATCH stanza.
     342              :  * 3. Early termination of the calling query, for example due to LIMIT,
     343              :  *    or to a rescan of the calling plan node.  Then this is called via the
     344              :  *    ExprContext shutdown callback ShutdownPLyFunction.
     345              :  * 4. Error thrown from elsewhere in the query.  Then this is called during
     346              :  *    (sub)transaction abort via the memory-context reset callback
     347              :  *    RemovePLyProcedureCache.
     348              :  * (Some code paths hit more than one of these calls, which is why this
     349              :  * must tolerate the cleanup having been done already.)
     350              :  *
     351              :  * This argument presumes that the FmgrInfo the SRF is called from is in a
     352              :  * memory context that will be cleaned up by query abort.  Postgres does use
     353              :  * some longer-lived FmgrInfos, for instance those in relcache and typcache
     354              :  * entries.  But we never call SRFs via those.
     355              :  */
     356              : void
     357          915 : PLy_function_cleanup_srfstate(PLyProcedureCache *pcache)
     358              : {
     359          915 :     PLySRFState *srfstate = pcache->srfstate;
     360              : 
     361          915 :     if (srfstate != NULL)
     362              :     {
     363              :         /* Release refcount on the iter, if we still have one */
     364           57 :         Py_XDECREF(srfstate->iter);
     365           57 :         srfstate->iter = NULL;
     366              : 
     367              :         /* And drop any saved args; we won't need them */
     368           57 :         if (srfstate->savedargs)
     369            3 :             PLy_function_drop_args(srfstate->savedargs);
     370           57 :         srfstate->savedargs = NULL;
     371              : 
     372           57 :         pfree(srfstate);
     373           57 :         pcache->srfstate = NULL;
     374              :     }
     375          915 : }
     376              : 
     377              : /*
     378              :  * trigger subhandler
     379              :  *
     380              :  * the python function is expected to return Py_None if the tuple is
     381              :  * acceptable and unmodified.  Otherwise it should return a PyUnicode
     382              :  * object who's value is SKIP, or MODIFY.  SKIP means don't perform
     383              :  * this action.  MODIFY means the tuple has been modified, so update
     384              :  * tuple and perform action.  SKIP and MODIFY assume the trigger fires
     385              :  * BEFORE the event and is ROW level.  postgres expects the function
     386              :  * to take no arguments and return an argument of type trigger.
     387              :  */
     388              : HeapTuple
     389           49 : PLy_exec_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
     390              : {
     391           49 :     HeapTuple   rv = NULL;
     392           49 :     PyObject   *volatile plargs = NULL;
     393           49 :     PyObject   *volatile plrv = NULL;
     394              :     TriggerData *tdata;
     395              :     TupleDesc   rel_descr;
     396              : 
     397              :     Assert(CALLED_AS_TRIGGER(fcinfo));
     398           49 :     tdata = (TriggerData *) fcinfo->context;
     399              : 
     400              :     /*
     401              :      * Input/output conversion for trigger tuples.  We use the result and
     402              :      * result_in fields to store the tuple conversion info.  We do this over
     403              :      * again on each call to cover the possibility that the relation's tupdesc
     404              :      * changed since the trigger was last called.  The PLy_xxx_setup_func
     405              :      * calls should only happen once, but PLy_input_setup_tuple and
     406              :      * PLy_output_setup_tuple are responsible for not doing repetitive work.
     407              :      */
     408           49 :     rel_descr = RelationGetDescr(tdata->tg_relation);
     409           49 :     if (proc->result.typoid != rel_descr->tdtypeid)
     410           29 :         PLy_output_setup_func(&proc->result, proc->mcxt,
     411              :                               rel_descr->tdtypeid,
     412              :                               rel_descr->tdtypmod,
     413              :                               proc);
     414           49 :     if (proc->result_in.typoid != rel_descr->tdtypeid)
     415           29 :         PLy_input_setup_func(&proc->result_in, proc->mcxt,
     416              :                              rel_descr->tdtypeid,
     417              :                              rel_descr->tdtypmod,
     418              :                              proc);
     419           49 :     PLy_output_setup_tuple(&proc->result, rel_descr, proc);
     420           49 :     PLy_input_setup_tuple(&proc->result_in, rel_descr, proc);
     421              : 
     422              :     /*
     423              :      * If the trigger is called recursively, we must push outer-level
     424              :      * arguments into the stack.  This must be immediately before the PG_TRY
     425              :      * to ensure that the corresponding pop happens.
     426              :      */
     427           49 :     PLy_global_args_push(proc);
     428              : 
     429           49 :     PG_TRY();
     430              :     {
     431              :         int         rc PG_USED_FOR_ASSERTS_ONLY;
     432              : 
     433           49 :         rc = SPI_register_trigger_data(tdata);
     434              :         Assert(rc >= 0);
     435              : 
     436           49 :         plargs = PLy_trigger_build_args(fcinfo, proc, &rv);
     437           49 :         plrv = PLy_procedure_call(proc, "TD", plargs);
     438              : 
     439              :         Assert(plrv != NULL);
     440              : 
     441              :         /*
     442              :          * Disconnect from SPI manager
     443              :          */
     444           49 :         if (SPI_finish() != SPI_OK_FINISH)
     445            0 :             elog(ERROR, "SPI_finish failed");
     446              : 
     447              :         /*
     448              :          * return of None means we're happy with the tuple
     449              :          */
     450           49 :         if (plrv != Py_None)
     451              :         {
     452              :             char       *srv;
     453              : 
     454           25 :             if (PyUnicode_Check(plrv))
     455           24 :                 srv = PLyUnicode_AsString(plrv);
     456              :             else
     457              :             {
     458            1 :                 ereport(ERROR,
     459              :                         (errcode(ERRCODE_DATA_EXCEPTION),
     460              :                          errmsg("unexpected return value from trigger procedure"),
     461              :                          errdetail("Expected None or a string.")));
     462              :                 srv = NULL;     /* keep compiler quiet */
     463              :             }
     464              : 
     465           24 :             if (pg_strcasecmp(srv, "SKIP") == 0)
     466            1 :                 rv = NULL;
     467           23 :             else if (pg_strcasecmp(srv, "MODIFY") == 0)
     468              :             {
     469           21 :                 if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event) ||
     470            9 :                     TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
     471           20 :                     rv = PLy_modify_tuple(proc, plargs, tdata, rv);
     472              :                 else
     473            1 :                     ereport(WARNING,
     474              :                             (errmsg("PL/Python trigger function returned \"MODIFY\" in a DELETE trigger -- ignored")));
     475              :             }
     476            2 :             else if (pg_strcasecmp(srv, "OK") != 0)
     477              :             {
     478              :                 /*
     479              :                  * accept "OK" as an alternative to None; otherwise, raise an
     480              :                  * error
     481              :                  */
     482            2 :                 ereport(ERROR,
     483              :                         (errcode(ERRCODE_DATA_EXCEPTION),
     484              :                          errmsg("unexpected return value from trigger procedure"),
     485              :                          errdetail("Expected None, \"OK\", \"SKIP\", or \"MODIFY\".")));
     486              :             }
     487              :         }
     488              :     }
     489            9 :     PG_FINALLY();
     490              :     {
     491           49 :         PLy_global_args_pop(proc);
     492           49 :         Py_XDECREF(plargs);
     493           49 :         Py_XDECREF(plrv);
     494              :     }
     495           49 :     PG_END_TRY();
     496              : 
     497           40 :     return rv;
     498              : }
     499              : 
     500              : /*
     501              :  * event trigger subhandler
     502              :  */
     503              : void
     504           10 : PLy_exec_event_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
     505              : {
     506              :     EventTriggerData *tdata;
     507           10 :     PyObject   *volatile pltdata = NULL;
     508              : 
     509              :     Assert(CALLED_AS_EVENT_TRIGGER(fcinfo));
     510           10 :     tdata = (EventTriggerData *) fcinfo->context;
     511              : 
     512           10 :     PG_TRY();
     513              :     {
     514              :         PyObject   *pltevent,
     515              :                    *plttag;
     516              : 
     517           10 :         pltdata = PyDict_New();
     518           10 :         if (!pltdata)
     519            0 :             PLy_elog(ERROR, NULL);
     520              : 
     521           10 :         pltevent = PLyUnicode_FromString(tdata->event);
     522           10 :         PyDict_SetItemString(pltdata, "event", pltevent);
     523              :         Py_DECREF(pltevent);
     524              : 
     525           10 :         plttag = PLyUnicode_FromString(GetCommandTagName(tdata->tag));
     526           10 :         PyDict_SetItemString(pltdata, "tag", plttag);
     527              :         Py_DECREF(plttag);
     528              : 
     529           10 :         PLy_procedure_call(proc, "TD", pltdata);
     530              : 
     531           10 :         if (SPI_finish() != SPI_OK_FINISH)
     532            0 :             elog(ERROR, "SPI_finish() failed");
     533              :     }
     534            0 :     PG_FINALLY();
     535              :     {
     536           10 :         Py_XDECREF(pltdata);
     537              :     }
     538           10 :     PG_END_TRY();
     539           10 : }
     540              : 
     541              : /* helper functions for Python code execution */
     542              : 
     543              : static PyObject *
     544          517 : PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
     545              : {
     546          517 :     PyObject   *volatile arg = NULL;
     547              :     PyObject   *args;
     548              :     int         i;
     549              : 
     550              :     /*
     551              :      * Make any Py*_New() calls before the PG_TRY block so that we can quickly
     552              :      * return NULL on failure.  We can't return within the PG_TRY block, else
     553              :      * we'd miss unwinding the exception stack.
     554              :      */
     555          517 :     args = PyList_New(proc->nargs);
     556          517 :     if (!args)
     557            0 :         return NULL;
     558              : 
     559          517 :     PG_TRY();
     560              :     {
     561         1234 :         for (i = 0; i < proc->nargs; i++)
     562              :         {
     563          717 :             PLyDatumToOb *arginfo = &proc->args[i];
     564              : 
     565          717 :             if (fcinfo->args[i].isnull)
     566          121 :                 arg = NULL;
     567              :             else
     568          596 :                 arg = PLy_input_convert(arginfo, fcinfo->args[i].value);
     569              : 
     570          717 :             if (arg == NULL)
     571              :             {
     572              :                 Py_INCREF(Py_None);
     573          121 :                 arg = Py_None;
     574              :             }
     575              : 
     576          717 :             if (PyList_SetItem(args, i, arg) == -1)
     577            0 :                 PLy_elog(ERROR, "PyList_SetItem() failed, while setting up arguments");
     578              : 
     579          717 :             if (proc->argnames && proc->argnames[i] &&
     580          714 :                 PyDict_SetItemString(proc->globals, proc->argnames[i], arg) == -1)
     581            0 :                 PLy_elog(ERROR, "PyDict_SetItemString() failed, while setting up arguments");
     582          717 :             arg = NULL;
     583              :         }
     584              :     }
     585            0 :     PG_CATCH();
     586              :     {
     587            0 :         Py_XDECREF(arg);
     588            0 :         Py_XDECREF(args);
     589              : 
     590            0 :         PG_RE_THROW();
     591              :     }
     592          517 :     PG_END_TRY();
     593              : 
     594          517 :     return args;
     595              : }
     596              : 
     597              : /*
     598              :  * Construct a PLySavedArgs struct representing the current values of the
     599              :  * procedure's arguments in its globals dict.  This can be used to restore
     600              :  * those values when exiting a recursive call level or returning control to a
     601              :  * set-returning function.
     602              :  *
     603              :  * This would not be necessary except for an ancient decision to make args
     604              :  * available via the proc's globals :-( ... but we're stuck with that now.
     605              :  */
     606              : static PLySavedArgs *
     607          169 : PLy_function_save_args(PLyProcedure *proc)
     608              : {
     609              :     PLySavedArgs *result;
     610              : 
     611              :     /* saved args are always allocated in procedure's context */
     612              :     result = (PLySavedArgs *)
     613          169 :         MemoryContextAllocZero(proc->mcxt,
     614          169 :                                offsetof(PLySavedArgs, namedargs) +
     615          169 :                                proc->nargs * sizeof(PyObject *));
     616          169 :     result->nargs = proc->nargs;
     617              : 
     618              :     /* Fetch the "args" list */
     619          169 :     result->args = PyDict_GetItemString(proc->globals, "args");
     620          169 :     Py_XINCREF(result->args);
     621              : 
     622              :     /* If it's a trigger, also save "TD" */
     623          169 :     if (proc->is_trigger == PLPY_TRIGGER)
     624              :     {
     625            1 :         result->td = PyDict_GetItemString(proc->globals, "TD");
     626            1 :         Py_XINCREF(result->td);
     627              :     }
     628              : 
     629              :     /* Fetch all the named arguments */
     630          169 :     if (proc->argnames)
     631              :     {
     632              :         int         i;
     633              : 
     634          319 :         for (i = 0; i < result->nargs; i++)
     635              :         {
     636          219 :             if (proc->argnames[i])
     637              :             {
     638          438 :                 result->namedargs[i] = PyDict_GetItemString(proc->globals,
     639          219 :                                                             proc->argnames[i]);
     640          219 :                 Py_XINCREF(result->namedargs[i]);
     641              :             }
     642              :         }
     643              :     }
     644              : 
     645          169 :     return result;
     646              : }
     647              : 
     648              : /*
     649              :  * Restore procedure's arguments from a PLySavedArgs struct,
     650              :  * then free the struct.
     651              :  */
     652              : static void
     653          166 : PLy_function_restore_args(PLyProcedure *proc, PLySavedArgs *savedargs)
     654              : {
     655              :     /* Restore named arguments into their slots in the globals dict */
     656          166 :     if (proc->argnames)
     657              :     {
     658              :         int         i;
     659              : 
     660          319 :         for (i = 0; i < savedargs->nargs; i++)
     661              :         {
     662          219 :             if (proc->argnames[i] && savedargs->namedargs[i])
     663              :             {
     664          219 :                 PyDict_SetItemString(proc->globals, proc->argnames[i],
     665              :                                      savedargs->namedargs[i]);
     666          219 :                 Py_DECREF(savedargs->namedargs[i]);
     667              :             }
     668              :         }
     669              :     }
     670              : 
     671              :     /* Restore the "args" object, too */
     672          166 :     if (savedargs->args)
     673              :     {
     674          165 :         PyDict_SetItemString(proc->globals, "args", savedargs->args);
     675          165 :         Py_DECREF(savedargs->args);
     676              :     }
     677              : 
     678              :     /* Restore the "TD" object, too */
     679          166 :     if (savedargs->td)
     680              :     {
     681            1 :         PyDict_SetItemString(proc->globals, "TD", savedargs->td);
     682            1 :         Py_DECREF(savedargs->td);
     683              :     }
     684              : 
     685              :     /* And free the PLySavedArgs struct */
     686          166 :     pfree(savedargs);
     687          166 : }
     688              : 
     689              : /*
     690              :  * Free a PLySavedArgs struct without restoring the values.
     691              :  */
     692              : static void
     693            3 : PLy_function_drop_args(PLySavedArgs *savedargs)
     694              : {
     695              :     int         i;
     696              : 
     697              :     /* Drop references for named args */
     698            3 :     for (i = 0; i < savedargs->nargs; i++)
     699              :     {
     700            0 :         Py_XDECREF(savedargs->namedargs[i]);
     701              :     }
     702              : 
     703              :     /* Drop refs to the "args" and "TD" objects, too */
     704            3 :     Py_XDECREF(savedargs->args);
     705            3 :     Py_XDECREF(savedargs->td);
     706              : 
     707              :     /* And free the PLySavedArgs struct */
     708            3 :     pfree(savedargs);
     709            3 : }
     710              : 
     711              : /*
     712              :  * Save away any existing arguments for the given procedure, so that we can
     713              :  * install new values for a recursive call.  This should be invoked before
     714              :  * doing PLy_function_build_args() or PLy_trigger_build_args().
     715              :  *
     716              :  * NB: callers must ensure that PLy_global_args_pop gets invoked once, and
     717              :  * only once, per successful completion of PLy_global_args_push.  Otherwise
     718              :  * we'll end up out-of-sync between the actual call stack and the contents
     719              :  * of proc->argstack.
     720              :  */
     721              : static void
     722          722 : PLy_global_args_push(PLyProcedure *proc)
     723              : {
     724              :     /* We only need to push if we are already inside some active call */
     725          722 :     if (proc->calldepth > 0)
     726              :     {
     727              :         PLySavedArgs *node;
     728              : 
     729              :         /* Build a struct containing current argument values */
     730           10 :         node = PLy_function_save_args(proc);
     731              : 
     732              :         /*
     733              :          * Push the saved argument values into the procedure's stack.  Once we
     734              :          * modify either proc->argstack or proc->calldepth, we had better
     735              :          * return without the possibility of error.
     736              :          */
     737           10 :         node->next = proc->argstack;
     738           10 :         proc->argstack = node;
     739              :     }
     740          722 :     proc->calldepth++;
     741          722 : }
     742              : 
     743              : /*
     744              :  * Pop old arguments when exiting a recursive call.
     745              :  *
     746              :  * Note: the idea here is to adjust the proc's callstack state before doing
     747              :  * anything that could possibly fail.  In event of any error, we want the
     748              :  * callstack to look like we've done the pop.  Leaking a bit of memory is
     749              :  * tolerable.
     750              :  */
     751              : static void
     752          722 : PLy_global_args_pop(PLyProcedure *proc)
     753              : {
     754              :     Assert(proc->calldepth > 0);
     755              :     /* We only need to pop if we were already inside some active call */
     756          722 :     if (proc->calldepth > 1)
     757              :     {
     758           10 :         PLySavedArgs *ptr = proc->argstack;
     759              : 
     760              :         /* Pop the callstack */
     761              :         Assert(ptr != NULL);
     762           10 :         proc->argstack = ptr->next;
     763           10 :         proc->calldepth--;
     764              : 
     765              :         /* Restore argument values, then free ptr */
     766           10 :         PLy_function_restore_args(proc, ptr);
     767              :     }
     768              :     else
     769              :     {
     770              :         /* Exiting call depth 1 */
     771              :         Assert(proc->argstack == NULL);
     772          712 :         proc->calldepth--;
     773              : 
     774              :         /*
     775              :          * We used to delete the named arguments (but not "args") from the
     776              :          * proc's globals dict when exiting the outermost call level for a
     777              :          * function.  This seems rather pointless though: nothing can see the
     778              :          * dict until the function is called again, at which time we'll
     779              :          * overwrite those dict entries.  So don't bother with that.
     780              :          */
     781              :     }
     782          722 : }
     783              : 
     784              : static void
     785           37 : plpython_return_error_callback(void *arg)
     786              : {
     787           37 :     PLyExecutionContext *exec_ctx = PLy_current_execution_context();
     788              : 
     789           37 :     if (exec_ctx->curr_proc &&
     790           37 :         !exec_ctx->curr_proc->is_procedure)
     791           36 :         errcontext("while creating return value");
     792           37 : }
     793              : 
     794              : static PyObject *
     795           49 : PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *rv)
     796              : {
     797           49 :     TriggerData *tdata = (TriggerData *) fcinfo->context;
     798           49 :     TupleDesc   rel_descr = RelationGetDescr(tdata->tg_relation);
     799              :     PyObject   *pltname,
     800              :                *pltevent,
     801              :                *pltwhen,
     802              :                *pltlevel,
     803              :                *pltrelid,
     804              :                *plttablename,
     805              :                *plttableschema,
     806              :                *pltargs,
     807              :                *pytnew,
     808              :                *pytold,
     809              :                *pltdata;
     810              :     char       *stroid;
     811              : 
     812              :     /*
     813              :      * Make any Py*_New() calls before the PG_TRY block so that we can quickly
     814              :      * return NULL on failure.  We can't return within the PG_TRY block, else
     815              :      * we'd miss unwinding the exception stack.
     816              :      */
     817           49 :     pltdata = PyDict_New();
     818           49 :     if (!pltdata)
     819            0 :         return NULL;
     820              : 
     821           49 :     if (tdata->tg_trigger->tgnargs)
     822              :     {
     823           16 :         pltargs = PyList_New(tdata->tg_trigger->tgnargs);
     824           16 :         if (!pltargs)
     825              :         {
     826              :             Py_DECREF(pltdata);
     827            0 :             return NULL;
     828              :         }
     829              :     }
     830              :     else
     831              :     {
     832              :         Py_INCREF(Py_None);
     833           33 :         pltargs = Py_None;
     834              :     }
     835              : 
     836           49 :     PG_TRY();
     837              :     {
     838           49 :         pltname = PLyUnicode_FromString(tdata->tg_trigger->tgname);
     839           49 :         PyDict_SetItemString(pltdata, "name", pltname);
     840              :         Py_DECREF(pltname);
     841              : 
     842           49 :         stroid = DatumGetCString(DirectFunctionCall1(oidout,
     843              :                                                      ObjectIdGetDatum(tdata->tg_relation->rd_id)));
     844           49 :         pltrelid = PLyUnicode_FromString(stroid);
     845           49 :         PyDict_SetItemString(pltdata, "relid", pltrelid);
     846              :         Py_DECREF(pltrelid);
     847           49 :         pfree(stroid);
     848              : 
     849           49 :         stroid = SPI_getrelname(tdata->tg_relation);
     850           49 :         plttablename = PLyUnicode_FromString(stroid);
     851           49 :         PyDict_SetItemString(pltdata, "table_name", plttablename);
     852              :         Py_DECREF(plttablename);
     853           49 :         pfree(stroid);
     854              : 
     855           49 :         stroid = SPI_getnspname(tdata->tg_relation);
     856           49 :         plttableschema = PLyUnicode_FromString(stroid);
     857           49 :         PyDict_SetItemString(pltdata, "table_schema", plttableschema);
     858              :         Py_DECREF(plttableschema);
     859           49 :         pfree(stroid);
     860              : 
     861           49 :         if (TRIGGER_FIRED_BEFORE(tdata->tg_event))
     862           36 :             pltwhen = PLyUnicode_FromString("BEFORE");
     863           13 :         else if (TRIGGER_FIRED_AFTER(tdata->tg_event))
     864           10 :             pltwhen = PLyUnicode_FromString("AFTER");
     865            3 :         else if (TRIGGER_FIRED_INSTEAD(tdata->tg_event))
     866            3 :             pltwhen = PLyUnicode_FromString("INSTEAD OF");
     867              :         else
     868              :         {
     869            0 :             elog(ERROR, "unrecognized WHEN tg_event: %u", tdata->tg_event);
     870              :             pltwhen = NULL;     /* keep compiler quiet */
     871              :         }
     872           49 :         PyDict_SetItemString(pltdata, "when", pltwhen);
     873              :         Py_DECREF(pltwhen);
     874              : 
     875           49 :         if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
     876              :         {
     877           44 :             pltlevel = PLyUnicode_FromString("ROW");
     878           44 :             PyDict_SetItemString(pltdata, "level", pltlevel);
     879              :             Py_DECREF(pltlevel);
     880              : 
     881              :             /*
     882              :              * Note: In BEFORE trigger, stored generated columns are not
     883              :              * computed yet, so don't make them accessible in NEW row.
     884              :              */
     885              : 
     886           44 :             if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
     887              :             {
     888           21 :                 pltevent = PLyUnicode_FromString("INSERT");
     889              : 
     890           21 :                 PyDict_SetItemString(pltdata, "old", Py_None);
     891           42 :                 pytnew = PLy_input_from_tuple(&proc->result_in,
     892              :                                               tdata->tg_trigtuple,
     893              :                                               rel_descr,
     894           21 :                                               !TRIGGER_FIRED_BEFORE(tdata->tg_event));
     895           21 :                 PyDict_SetItemString(pltdata, "new", pytnew);
     896              :                 Py_DECREF(pytnew);
     897           21 :                 *rv = tdata->tg_trigtuple;
     898              :             }
     899           23 :             else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
     900              :             {
     901            6 :                 pltevent = PLyUnicode_FromString("DELETE");
     902              : 
     903            6 :                 PyDict_SetItemString(pltdata, "new", Py_None);
     904            6 :                 pytold = PLy_input_from_tuple(&proc->result_in,
     905              :                                               tdata->tg_trigtuple,
     906              :                                               rel_descr,
     907              :                                               true);
     908            6 :                 PyDict_SetItemString(pltdata, "old", pytold);
     909              :                 Py_DECREF(pytold);
     910            6 :                 *rv = tdata->tg_trigtuple;
     911              :             }
     912           17 :             else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
     913              :             {
     914           17 :                 pltevent = PLyUnicode_FromString("UPDATE");
     915              : 
     916           34 :                 pytnew = PLy_input_from_tuple(&proc->result_in,
     917              :                                               tdata->tg_newtuple,
     918              :                                               rel_descr,
     919           17 :                                               !TRIGGER_FIRED_BEFORE(tdata->tg_event));
     920           17 :                 PyDict_SetItemString(pltdata, "new", pytnew);
     921              :                 Py_DECREF(pytnew);
     922           17 :                 pytold = PLy_input_from_tuple(&proc->result_in,
     923              :                                               tdata->tg_trigtuple,
     924              :                                               rel_descr,
     925              :                                               true);
     926           17 :                 PyDict_SetItemString(pltdata, "old", pytold);
     927              :                 Py_DECREF(pytold);
     928           17 :                 *rv = tdata->tg_newtuple;
     929              :             }
     930              :             else
     931              :             {
     932            0 :                 elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
     933              :                 pltevent = NULL;    /* keep compiler quiet */
     934              :             }
     935              : 
     936           44 :             PyDict_SetItemString(pltdata, "event", pltevent);
     937              :             Py_DECREF(pltevent);
     938              :         }
     939            5 :         else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))
     940              :         {
     941            5 :             pltlevel = PLyUnicode_FromString("STATEMENT");
     942            5 :             PyDict_SetItemString(pltdata, "level", pltlevel);
     943              :             Py_DECREF(pltlevel);
     944              : 
     945            5 :             PyDict_SetItemString(pltdata, "old", Py_None);
     946            5 :             PyDict_SetItemString(pltdata, "new", Py_None);
     947            5 :             *rv = NULL;
     948              : 
     949            5 :             if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
     950            1 :                 pltevent = PLyUnicode_FromString("INSERT");
     951            4 :             else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
     952            1 :                 pltevent = PLyUnicode_FromString("DELETE");
     953            3 :             else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
     954            2 :                 pltevent = PLyUnicode_FromString("UPDATE");
     955            1 :             else if (TRIGGER_FIRED_BY_TRUNCATE(tdata->tg_event))
     956            1 :                 pltevent = PLyUnicode_FromString("TRUNCATE");
     957              :             else
     958              :             {
     959            0 :                 elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
     960              :                 pltevent = NULL;    /* keep compiler quiet */
     961              :             }
     962              : 
     963            5 :             PyDict_SetItemString(pltdata, "event", pltevent);
     964              :             Py_DECREF(pltevent);
     965              :         }
     966              :         else
     967            0 :             elog(ERROR, "unrecognized LEVEL tg_event: %u", tdata->tg_event);
     968              : 
     969           49 :         if (tdata->tg_trigger->tgnargs)
     970              :         {
     971              :             /*
     972              :              * all strings...
     973              :              */
     974              :             int         i;
     975              :             PyObject   *pltarg;
     976              : 
     977              :             /* pltargs should have been allocated before the PG_TRY block. */
     978              :             Assert(pltargs && pltargs != Py_None);
     979              : 
     980           45 :             for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
     981              :             {
     982           29 :                 pltarg = PLyUnicode_FromString(tdata->tg_trigger->tgargs[i]);
     983              : 
     984              :                 /*
     985              :                  * stolen, don't Py_DECREF
     986              :                  */
     987           29 :                 PyList_SetItem(pltargs, i, pltarg);
     988              :             }
     989              :         }
     990              :         else
     991              :         {
     992              :             Assert(pltargs == Py_None);
     993              :         }
     994           49 :         PyDict_SetItemString(pltdata, "args", pltargs);
     995              :         Py_DECREF(pltargs);
     996              :     }
     997            0 :     PG_CATCH();
     998              :     {
     999            0 :         Py_XDECREF(pltargs);
    1000            0 :         Py_XDECREF(pltdata);
    1001            0 :         PG_RE_THROW();
    1002              :     }
    1003           49 :     PG_END_TRY();
    1004              : 
    1005           49 :     return pltdata;
    1006              : }
    1007              : 
    1008              : /*
    1009              :  * Apply changes requested by a MODIFY return from a trigger function.
    1010              :  */
    1011              : static HeapTuple
    1012           20 : PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
    1013              :                  HeapTuple otup)
    1014              : {
    1015              :     HeapTuple   rtup;
    1016              :     PyObject   *volatile plntup;
    1017              :     PyObject   *volatile plkeys;
    1018              :     PyObject   *volatile plval;
    1019              :     Datum      *volatile modvalues;
    1020              :     bool       *volatile modnulls;
    1021              :     bool       *volatile modrepls;
    1022              :     ErrorContextCallback plerrcontext;
    1023              : 
    1024           20 :     plerrcontext.callback = plpython_trigger_error_callback;
    1025           20 :     plerrcontext.previous = error_context_stack;
    1026           20 :     error_context_stack = &plerrcontext;
    1027              : 
    1028           20 :     plntup = plkeys = plval = NULL;
    1029           20 :     modvalues = NULL;
    1030           20 :     modnulls = NULL;
    1031           20 :     modrepls = NULL;
    1032              : 
    1033           20 :     PG_TRY();
    1034              :     {
    1035              :         TupleDesc   tupdesc;
    1036              :         int         nkeys,
    1037              :                     i;
    1038              : 
    1039           20 :         if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
    1040            1 :             ereport(ERROR,
    1041              :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    1042              :                      errmsg("TD[\"new\"] deleted, cannot modify row")));
    1043           19 :         Py_INCREF(plntup);
    1044           19 :         if (!PyDict_Check(plntup))
    1045            1 :             ereport(ERROR,
    1046              :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    1047              :                      errmsg("TD[\"new\"] is not a dictionary")));
    1048              : 
    1049           18 :         plkeys = PyDict_Keys(plntup);
    1050           18 :         nkeys = PyList_Size(plkeys);
    1051              : 
    1052           18 :         tupdesc = RelationGetDescr(tdata->tg_relation);
    1053              : 
    1054           18 :         modvalues = (Datum *) palloc0(tupdesc->natts * sizeof(Datum));
    1055           18 :         modnulls = (bool *) palloc0(tupdesc->natts * sizeof(bool));
    1056           18 :         modrepls = (bool *) palloc0(tupdesc->natts * sizeof(bool));
    1057              : 
    1058           45 :         for (i = 0; i < nkeys; i++)
    1059              :         {
    1060              :             PyObject   *platt;
    1061              :             char       *plattstr;
    1062              :             int         attn;
    1063              :             PLyObToDatum *att;
    1064              : 
    1065           31 :             platt = PyList_GetItem(plkeys, i);
    1066           31 :             if (PyUnicode_Check(platt))
    1067           30 :                 plattstr = PLyUnicode_AsString(platt);
    1068              :             else
    1069              :             {
    1070            1 :                 ereport(ERROR,
    1071              :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    1072              :                          errmsg("TD[\"new\"] dictionary key at ordinal position %d is not a string", i)));
    1073              :                 plattstr = NULL;    /* keep compiler quiet */
    1074              :             }
    1075           30 :             attn = SPI_fnumber(tupdesc, plattstr);
    1076           30 :             if (attn == SPI_ERROR_NOATTRIBUTE)
    1077            2 :                 ereport(ERROR,
    1078              :                         (errcode(ERRCODE_UNDEFINED_COLUMN),
    1079              :                          errmsg("key \"%s\" found in TD[\"new\"] does not exist as a column in the triggering row",
    1080              :                                 plattstr)));
    1081           28 :             if (attn <= 0)
    1082            0 :                 ereport(ERROR,
    1083              :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1084              :                          errmsg("cannot set system attribute \"%s\"",
    1085              :                                 plattstr)));
    1086           28 :             if (TupleDescAttr(tupdesc, attn - 1)->attgenerated)
    1087            1 :                 ereport(ERROR,
    1088              :                         (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
    1089              :                          errmsg("cannot set generated column \"%s\"",
    1090              :                                 plattstr)));
    1091              : 
    1092           27 :             plval = PyDict_GetItem(plntup, platt);
    1093           27 :             if (plval == NULL)
    1094            0 :                 elog(FATAL, "Python interpreter is probably corrupted");
    1095              : 
    1096           27 :             Py_INCREF(plval);
    1097              : 
    1098              :             /* We assume proc->result is set up to convert tuples properly */
    1099           27 :             att = &proc->result.tuple.atts[attn - 1];
    1100              : 
    1101           54 :             modvalues[attn - 1] = PLy_output_convert(att,
    1102              :                                                      plval,
    1103           27 :                                                      &modnulls[attn - 1]);
    1104           27 :             modrepls[attn - 1] = true;
    1105              : 
    1106           27 :             Py_DECREF(plval);
    1107           27 :             plval = NULL;
    1108              :         }
    1109              : 
    1110           14 :         rtup = heap_modify_tuple(otup, tupdesc, modvalues, modnulls, modrepls);
    1111              :     }
    1112            6 :     PG_CATCH();
    1113              :     {
    1114            6 :         Py_XDECREF(plntup);
    1115            6 :         Py_XDECREF(plkeys);
    1116            6 :         Py_XDECREF(plval);
    1117              : 
    1118            6 :         if (modvalues)
    1119            4 :             pfree(modvalues);
    1120            6 :         if (modnulls)
    1121            4 :             pfree(modnulls);
    1122            6 :         if (modrepls)
    1123            4 :             pfree(modrepls);
    1124              : 
    1125            6 :         PG_RE_THROW();
    1126              :     }
    1127           14 :     PG_END_TRY();
    1128              : 
    1129           14 :     Py_DECREF(plntup);
    1130           14 :     Py_DECREF(plkeys);
    1131              : 
    1132           14 :     pfree(modvalues);
    1133           14 :     pfree(modnulls);
    1134           14 :     pfree(modrepls);
    1135              : 
    1136           14 :     error_context_stack = plerrcontext.previous;
    1137              : 
    1138           14 :     return rtup;
    1139              : }
    1140              : 
    1141              : static void
    1142            6 : plpython_trigger_error_callback(void *arg)
    1143              : {
    1144            6 :     PLyExecutionContext *exec_ctx = PLy_current_execution_context();
    1145              : 
    1146            6 :     if (exec_ctx->curr_proc)
    1147            6 :         errcontext("while modifying trigger row");
    1148            6 : }
    1149              : 
    1150              : /* execute Python code, propagate Python errors to the backend */
    1151              : static PyObject *
    1152          576 : PLy_procedure_call(PLyProcedure *proc, const char *kargs, PyObject *vargs)
    1153              : {
    1154          576 :     PyObject   *rv = NULL;
    1155          576 :     int volatile save_subxact_level = list_length(explicit_subtransactions);
    1156              : 
    1157          576 :     PyDict_SetItemString(proc->globals, kargs, vargs);
    1158              : 
    1159          576 :     PG_TRY();
    1160              :     {
    1161          576 :         rv = PyEval_EvalCode(proc->code, proc->globals, proc->globals);
    1162              : 
    1163              :         /*
    1164              :          * Since plpy will only let you close subtransactions that you
    1165              :          * started, you cannot *unnest* subtransactions, only *nest* them
    1166              :          * without closing.
    1167              :          */
    1168              :         Assert(list_length(explicit_subtransactions) >= save_subxact_level);
    1169              :     }
    1170            0 :     PG_FINALLY();
    1171              :     {
    1172          576 :         PLy_abort_open_subtransactions(save_subxact_level);
    1173              :     }
    1174          576 :     PG_END_TRY();
    1175              : 
    1176              :     /* If the Python code returned an error, propagate it */
    1177          576 :     if (rv == NULL)
    1178           54 :         PLy_elog(ERROR, NULL);
    1179              : 
    1180          522 :     return rv;
    1181              : }
    1182              : 
    1183              : /*
    1184              :  * Abort lingering subtransactions that have been explicitly started
    1185              :  * by plpy.subtransaction().start() and not properly closed.
    1186              :  */
    1187              : static void
    1188          576 : PLy_abort_open_subtransactions(int save_subxact_level)
    1189              : {
    1190              :     Assert(save_subxact_level >= 0);
    1191              : 
    1192          582 :     while (list_length(explicit_subtransactions) > save_subxact_level)
    1193              :     {
    1194              :         PLySubtransactionData *subtransactiondata;
    1195              : 
    1196              :         Assert(explicit_subtransactions != NIL);
    1197              : 
    1198            6 :         ereport(WARNING,
    1199              :                 (errmsg("forcibly aborting a subtransaction that has not been exited")));
    1200              : 
    1201            6 :         RollbackAndReleaseCurrentSubTransaction();
    1202              : 
    1203            6 :         subtransactiondata = (PLySubtransactionData *) linitial(explicit_subtransactions);
    1204            6 :         explicit_subtransactions = list_delete_first(explicit_subtransactions);
    1205              : 
    1206            6 :         MemoryContextSwitchTo(subtransactiondata->oldcontext);
    1207            6 :         CurrentResourceOwner = subtransactiondata->oldowner;
    1208            6 :         pfree(subtransactiondata);
    1209              :     }
    1210          576 : }
        

Generated by: LCOV version 2.0-1