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

Generated by: LCOV version 2.0-1