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-02-28 14:14:49 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              : /* trigger subhandler
     310              :  *
     311              :  * the python function is expected to return Py_None if the tuple is
     312              :  * acceptable and unmodified.  Otherwise it should return a PyUnicode
     313              :  * object who's value is SKIP, or MODIFY.  SKIP means don't perform
     314              :  * this action.  MODIFY means the tuple has been modified, so update
     315              :  * tuple and perform action.  SKIP and MODIFY assume the trigger fires
     316              :  * BEFORE the event and is ROW level.  postgres expects the function
     317              :  * to take no arguments and return an argument of type trigger.
     318              :  */
     319              : HeapTuple
     320           49 : PLy_exec_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
     321              : {
     322           49 :     HeapTuple   rv = NULL;
     323           49 :     PyObject   *volatile plargs = NULL;
     324           49 :     PyObject   *volatile plrv = NULL;
     325              :     TriggerData *tdata;
     326              :     TupleDesc   rel_descr;
     327              : 
     328              :     Assert(CALLED_AS_TRIGGER(fcinfo));
     329           49 :     tdata = (TriggerData *) fcinfo->context;
     330              : 
     331              :     /*
     332              :      * Input/output conversion for trigger tuples.  We use the result and
     333              :      * result_in fields to store the tuple conversion info.  We do this over
     334              :      * again on each call to cover the possibility that the relation's tupdesc
     335              :      * changed since the trigger was last called.  The PLy_xxx_setup_func
     336              :      * calls should only happen once, but PLy_input_setup_tuple and
     337              :      * PLy_output_setup_tuple are responsible for not doing repetitive work.
     338              :      */
     339           49 :     rel_descr = RelationGetDescr(tdata->tg_relation);
     340           49 :     if (proc->result.typoid != rel_descr->tdtypeid)
     341           26 :         PLy_output_setup_func(&proc->result, proc->mcxt,
     342              :                               rel_descr->tdtypeid,
     343              :                               rel_descr->tdtypmod,
     344              :                               proc);
     345           49 :     if (proc->result_in.typoid != rel_descr->tdtypeid)
     346           26 :         PLy_input_setup_func(&proc->result_in, proc->mcxt,
     347              :                              rel_descr->tdtypeid,
     348              :                              rel_descr->tdtypmod,
     349              :                              proc);
     350           49 :     PLy_output_setup_tuple(&proc->result, rel_descr, proc);
     351           49 :     PLy_input_setup_tuple(&proc->result_in, rel_descr, proc);
     352              : 
     353              :     /*
     354              :      * If the trigger is called recursively, we must push outer-level
     355              :      * arguments into the stack.  This must be immediately before the PG_TRY
     356              :      * to ensure that the corresponding pop happens.
     357              :      */
     358           49 :     PLy_global_args_push(proc);
     359              : 
     360           49 :     PG_TRY();
     361              :     {
     362              :         int         rc PG_USED_FOR_ASSERTS_ONLY;
     363              : 
     364           49 :         rc = SPI_register_trigger_data(tdata);
     365              :         Assert(rc >= 0);
     366              : 
     367           49 :         plargs = PLy_trigger_build_args(fcinfo, proc, &rv);
     368           49 :         plrv = PLy_procedure_call(proc, "TD", plargs);
     369              : 
     370              :         Assert(plrv != NULL);
     371              : 
     372              :         /*
     373              :          * Disconnect from SPI manager
     374              :          */
     375           49 :         if (SPI_finish() != SPI_OK_FINISH)
     376            0 :             elog(ERROR, "SPI_finish failed");
     377              : 
     378              :         /*
     379              :          * return of None means we're happy with the tuple
     380              :          */
     381           49 :         if (plrv != Py_None)
     382              :         {
     383              :             char       *srv;
     384              : 
     385           25 :             if (PyUnicode_Check(plrv))
     386           24 :                 srv = PLyUnicode_AsString(plrv);
     387              :             else
     388              :             {
     389            1 :                 ereport(ERROR,
     390              :                         (errcode(ERRCODE_DATA_EXCEPTION),
     391              :                          errmsg("unexpected return value from trigger procedure"),
     392              :                          errdetail("Expected None or a string.")));
     393              :                 srv = NULL;     /* keep compiler quiet */
     394              :             }
     395              : 
     396           24 :             if (pg_strcasecmp(srv, "SKIP") == 0)
     397            1 :                 rv = NULL;
     398           23 :             else if (pg_strcasecmp(srv, "MODIFY") == 0)
     399              :             {
     400           21 :                 if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event) ||
     401            9 :                     TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
     402           20 :                     rv = PLy_modify_tuple(proc, plargs, tdata, rv);
     403              :                 else
     404            1 :                     ereport(WARNING,
     405              :                             (errmsg("PL/Python trigger function returned \"MODIFY\" in a DELETE trigger -- ignored")));
     406              :             }
     407            2 :             else if (pg_strcasecmp(srv, "OK") != 0)
     408              :             {
     409              :                 /*
     410              :                  * accept "OK" as an alternative to None; otherwise, raise an
     411              :                  * error
     412              :                  */
     413            2 :                 ereport(ERROR,
     414              :                         (errcode(ERRCODE_DATA_EXCEPTION),
     415              :                          errmsg("unexpected return value from trigger procedure"),
     416              :                          errdetail("Expected None, \"OK\", \"SKIP\", or \"MODIFY\".")));
     417              :             }
     418              :         }
     419              :     }
     420            9 :     PG_FINALLY();
     421              :     {
     422           49 :         PLy_global_args_pop(proc);
     423           49 :         Py_XDECREF(plargs);
     424           49 :         Py_XDECREF(plrv);
     425              :     }
     426           49 :     PG_END_TRY();
     427              : 
     428           40 :     return rv;
     429              : }
     430              : 
     431              : /*
     432              :  * event trigger subhandler
     433              :  */
     434              : void
     435           10 : PLy_exec_event_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
     436              : {
     437              :     EventTriggerData *tdata;
     438           10 :     PyObject   *volatile pltdata = NULL;
     439              : 
     440              :     Assert(CALLED_AS_EVENT_TRIGGER(fcinfo));
     441           10 :     tdata = (EventTriggerData *) fcinfo->context;
     442              : 
     443           10 :     PG_TRY();
     444              :     {
     445              :         PyObject   *pltevent,
     446              :                    *plttag;
     447              : 
     448           10 :         pltdata = PyDict_New();
     449           10 :         if (!pltdata)
     450            0 :             PLy_elog(ERROR, NULL);
     451              : 
     452           10 :         pltevent = PLyUnicode_FromString(tdata->event);
     453           10 :         PyDict_SetItemString(pltdata, "event", pltevent);
     454              :         Py_DECREF(pltevent);
     455              : 
     456           10 :         plttag = PLyUnicode_FromString(GetCommandTagName(tdata->tag));
     457           10 :         PyDict_SetItemString(pltdata, "tag", plttag);
     458              :         Py_DECREF(plttag);
     459              : 
     460           10 :         PLy_procedure_call(proc, "TD", pltdata);
     461              : 
     462           10 :         if (SPI_finish() != SPI_OK_FINISH)
     463            0 :             elog(ERROR, "SPI_finish() failed");
     464              :     }
     465            0 :     PG_FINALLY();
     466              :     {
     467           10 :         Py_XDECREF(pltdata);
     468              :     }
     469           10 :     PG_END_TRY();
     470           10 : }
     471              : 
     472              : /* helper functions for Python code execution */
     473              : 
     474              : static PyObject *
     475          513 : PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc)
     476              : {
     477          513 :     PyObject   *volatile arg = NULL;
     478              :     PyObject   *args;
     479              :     int         i;
     480              : 
     481              :     /*
     482              :      * Make any Py*_New() calls before the PG_TRY block so that we can quickly
     483              :      * return NULL on failure.  We can't return within the PG_TRY block, else
     484              :      * we'd miss unwinding the exception stack.
     485              :      */
     486          513 :     args = PyList_New(proc->nargs);
     487          513 :     if (!args)
     488            0 :         return NULL;
     489              : 
     490          513 :     PG_TRY();
     491              :     {
     492         1228 :         for (i = 0; i < proc->nargs; i++)
     493              :         {
     494          715 :             PLyDatumToOb *arginfo = &proc->args[i];
     495              : 
     496          715 :             if (fcinfo->args[i].isnull)
     497          121 :                 arg = NULL;
     498              :             else
     499          594 :                 arg = PLy_input_convert(arginfo, fcinfo->args[i].value);
     500              : 
     501          715 :             if (arg == NULL)
     502              :             {
     503              :                 Py_INCREF(Py_None);
     504          121 :                 arg = Py_None;
     505              :             }
     506              : 
     507          715 :             if (PyList_SetItem(args, i, arg) == -1)
     508            0 :                 PLy_elog(ERROR, "PyList_SetItem() failed, while setting up arguments");
     509              : 
     510          715 :             if (proc->argnames && proc->argnames[i] &&
     511          712 :                 PyDict_SetItemString(proc->globals, proc->argnames[i], arg) == -1)
     512            0 :                 PLy_elog(ERROR, "PyDict_SetItemString() failed, while setting up arguments");
     513          715 :             arg = NULL;
     514              :         }
     515              :     }
     516            0 :     PG_CATCH();
     517              :     {
     518            0 :         Py_XDECREF(arg);
     519            0 :         Py_XDECREF(args);
     520              : 
     521            0 :         PG_RE_THROW();
     522              :     }
     523          513 :     PG_END_TRY();
     524              : 
     525          513 :     return args;
     526              : }
     527              : 
     528              : /*
     529              :  * Construct a PLySavedArgs struct representing the current values of the
     530              :  * procedure's arguments in its globals dict.  This can be used to restore
     531              :  * those values when exiting a recursive call level or returning control to a
     532              :  * set-returning function.
     533              :  *
     534              :  * This would not be necessary except for an ancient decision to make args
     535              :  * available via the proc's globals :-( ... but we're stuck with that now.
     536              :  */
     537              : static PLySavedArgs *
     538          160 : PLy_function_save_args(PLyProcedure *proc)
     539              : {
     540              :     PLySavedArgs *result;
     541              : 
     542              :     /* saved args are always allocated in procedure's context */
     543              :     result = (PLySavedArgs *)
     544          160 :         MemoryContextAllocZero(proc->mcxt,
     545          160 :                                offsetof(PLySavedArgs, namedargs) +
     546          160 :                                proc->nargs * sizeof(PyObject *));
     547          160 :     result->nargs = proc->nargs;
     548              : 
     549              :     /* Fetch the "args" list */
     550          160 :     result->args = PyDict_GetItemString(proc->globals, "args");
     551          160 :     Py_XINCREF(result->args);
     552              : 
     553              :     /* If it's a trigger, also save "TD" */
     554          160 :     if (proc->is_trigger == PLPY_TRIGGER)
     555              :     {
     556            1 :         result->td = PyDict_GetItemString(proc->globals, "TD");
     557            1 :         Py_XINCREF(result->td);
     558              :     }
     559              : 
     560              :     /* Fetch all the named arguments */
     561          160 :     if (proc->argnames)
     562              :     {
     563              :         int         i;
     564              : 
     565          313 :         for (i = 0; i < result->nargs; i++)
     566              :         {
     567          216 :             if (proc->argnames[i])
     568              :             {
     569          432 :                 result->namedargs[i] = PyDict_GetItemString(proc->globals,
     570          216 :                                                             proc->argnames[i]);
     571          216 :                 Py_XINCREF(result->namedargs[i]);
     572              :             }
     573              :         }
     574              :     }
     575              : 
     576          160 :     return result;
     577              : }
     578              : 
     579              : /*
     580              :  * Restore procedure's arguments from a PLySavedArgs struct,
     581              :  * then free the struct.
     582              :  */
     583              : static void
     584          158 : PLy_function_restore_args(PLyProcedure *proc, PLySavedArgs *savedargs)
     585              : {
     586              :     /* Restore named arguments into their slots in the globals dict */
     587          158 :     if (proc->argnames)
     588              :     {
     589              :         int         i;
     590              : 
     591          313 :         for (i = 0; i < savedargs->nargs; i++)
     592              :         {
     593          216 :             if (proc->argnames[i] && savedargs->namedargs[i])
     594              :             {
     595          216 :                 PyDict_SetItemString(proc->globals, proc->argnames[i],
     596              :                                      savedargs->namedargs[i]);
     597          216 :                 Py_DECREF(savedargs->namedargs[i]);
     598              :             }
     599              :         }
     600              :     }
     601              : 
     602              :     /* Restore the "args" object, too */
     603          158 :     if (savedargs->args)
     604              :     {
     605          157 :         PyDict_SetItemString(proc->globals, "args", savedargs->args);
     606          157 :         Py_DECREF(savedargs->args);
     607              :     }
     608              : 
     609              :     /* Restore the "TD" object, too */
     610          158 :     if (savedargs->td)
     611              :     {
     612            1 :         PyDict_SetItemString(proc->globals, "TD", savedargs->td);
     613            1 :         Py_DECREF(savedargs->td);
     614              :     }
     615              : 
     616              :     /* And free the PLySavedArgs struct */
     617          158 :     pfree(savedargs);
     618          158 : }
     619              : 
     620              : /*
     621              :  * Free a PLySavedArgs struct without restoring the values.
     622              :  */
     623              : static void
     624            2 : PLy_function_drop_args(PLySavedArgs *savedargs)
     625              : {
     626              :     int         i;
     627              : 
     628              :     /* Drop references for named args */
     629            2 :     for (i = 0; i < savedargs->nargs; i++)
     630              :     {
     631            0 :         Py_XDECREF(savedargs->namedargs[i]);
     632              :     }
     633              : 
     634              :     /* Drop refs to the "args" and "TD" objects, too */
     635            2 :     Py_XDECREF(savedargs->args);
     636            2 :     Py_XDECREF(savedargs->td);
     637              : 
     638              :     /* And free the PLySavedArgs struct */
     639            2 :     pfree(savedargs);
     640            2 : }
     641              : 
     642              : /*
     643              :  * Save away any existing arguments for the given procedure, so that we can
     644              :  * install new values for a recursive call.  This should be invoked before
     645              :  * doing PLy_function_build_args() or PLy_trigger_build_args().
     646              :  *
     647              :  * NB: callers must ensure that PLy_global_args_pop gets invoked once, and
     648              :  * only once, per successful completion of PLy_global_args_push.  Otherwise
     649              :  * we'll end up out-of-sync between the actual call stack and the contents
     650              :  * of proc->argstack.
     651              :  */
     652              : static void
     653          709 : PLy_global_args_push(PLyProcedure *proc)
     654              : {
     655              :     /* We only need to push if we are already inside some active call */
     656          709 :     if (proc->calldepth > 0)
     657              :     {
     658              :         PLySavedArgs *node;
     659              : 
     660              :         /* Build a struct containing current argument values */
     661           11 :         node = PLy_function_save_args(proc);
     662              : 
     663              :         /*
     664              :          * Push the saved argument values into the procedure's stack.  Once we
     665              :          * modify either proc->argstack or proc->calldepth, we had better
     666              :          * return without the possibility of error.
     667              :          */
     668           11 :         node->next = proc->argstack;
     669           11 :         proc->argstack = node;
     670              :     }
     671          709 :     proc->calldepth++;
     672          709 : }
     673              : 
     674              : /*
     675              :  * Pop old arguments when exiting a recursive call.
     676              :  *
     677              :  * Note: the idea here is to adjust the proc's callstack state before doing
     678              :  * anything that could possibly fail.  In event of any error, we want the
     679              :  * callstack to look like we've done the pop.  Leaking a bit of memory is
     680              :  * tolerable.
     681              :  */
     682              : static void
     683          709 : PLy_global_args_pop(PLyProcedure *proc)
     684              : {
     685              :     Assert(proc->calldepth > 0);
     686              :     /* We only need to pop if we were already inside some active call */
     687          709 :     if (proc->calldepth > 1)
     688              :     {
     689           11 :         PLySavedArgs *ptr = proc->argstack;
     690              : 
     691              :         /* Pop the callstack */
     692              :         Assert(ptr != NULL);
     693           11 :         proc->argstack = ptr->next;
     694           11 :         proc->calldepth--;
     695              : 
     696              :         /* Restore argument values, then free ptr */
     697           11 :         PLy_function_restore_args(proc, ptr);
     698              :     }
     699              :     else
     700              :     {
     701              :         /* Exiting call depth 1 */
     702              :         Assert(proc->argstack == NULL);
     703          698 :         proc->calldepth--;
     704              : 
     705              :         /*
     706              :          * We used to delete the named arguments (but not "args") from the
     707              :          * proc's globals dict when exiting the outermost call level for a
     708              :          * function.  This seems rather pointless though: nothing can see the
     709              :          * dict until the function is called again, at which time we'll
     710              :          * overwrite those dict entries.  So don't bother with that.
     711              :          */
     712              :     }
     713          709 : }
     714              : 
     715              : /*
     716              :  * Memory context deletion callback for cleaning up a PLySRFState.
     717              :  * We need this in case execution of the SRF is terminated early,
     718              :  * due to error or the caller simply not running it to completion.
     719              :  */
     720              : static void
     721           53 : plpython_srf_cleanup_callback(void *arg)
     722              : {
     723           53 :     PLySRFState *srfstate = (PLySRFState *) arg;
     724              : 
     725              :     /* Release refcount on the iter, if we still have one */
     726           53 :     Py_XDECREF(srfstate->iter);
     727           53 :     srfstate->iter = NULL;
     728              :     /* And drop any saved args; we won't need them */
     729           53 :     if (srfstate->savedargs)
     730            0 :         PLy_function_drop_args(srfstate->savedargs);
     731           53 :     srfstate->savedargs = NULL;
     732           53 : }
     733              : 
     734              : static void
     735           37 : plpython_return_error_callback(void *arg)
     736              : {
     737           37 :     PLyExecutionContext *exec_ctx = PLy_current_execution_context();
     738              : 
     739           37 :     if (exec_ctx->curr_proc &&
     740           37 :         !exec_ctx->curr_proc->is_procedure)
     741           36 :         errcontext("while creating return value");
     742           37 : }
     743              : 
     744              : static PyObject *
     745           49 : PLy_trigger_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc, HeapTuple *rv)
     746              : {
     747           49 :     TriggerData *tdata = (TriggerData *) fcinfo->context;
     748           49 :     TupleDesc   rel_descr = RelationGetDescr(tdata->tg_relation);
     749              :     PyObject   *pltname,
     750              :                *pltevent,
     751              :                *pltwhen,
     752              :                *pltlevel,
     753              :                *pltrelid,
     754              :                *plttablename,
     755              :                *plttableschema,
     756              :                *pltargs,
     757              :                *pytnew,
     758              :                *pytold,
     759              :                *pltdata;
     760              :     char       *stroid;
     761              : 
     762              :     /*
     763              :      * Make any Py*_New() calls before the PG_TRY block so that we can quickly
     764              :      * return NULL on failure.  We can't return within the PG_TRY block, else
     765              :      * we'd miss unwinding the exception stack.
     766              :      */
     767           49 :     pltdata = PyDict_New();
     768           49 :     if (!pltdata)
     769            0 :         return NULL;
     770              : 
     771           49 :     if (tdata->tg_trigger->tgnargs)
     772              :     {
     773           16 :         pltargs = PyList_New(tdata->tg_trigger->tgnargs);
     774           16 :         if (!pltargs)
     775              :         {
     776              :             Py_DECREF(pltdata);
     777            0 :             return NULL;
     778              :         }
     779              :     }
     780              :     else
     781              :     {
     782              :         Py_INCREF(Py_None);
     783           33 :         pltargs = Py_None;
     784              :     }
     785              : 
     786           49 :     PG_TRY();
     787              :     {
     788           49 :         pltname = PLyUnicode_FromString(tdata->tg_trigger->tgname);
     789           49 :         PyDict_SetItemString(pltdata, "name", pltname);
     790              :         Py_DECREF(pltname);
     791              : 
     792           49 :         stroid = DatumGetCString(DirectFunctionCall1(oidout,
     793              :                                                      ObjectIdGetDatum(tdata->tg_relation->rd_id)));
     794           49 :         pltrelid = PLyUnicode_FromString(stroid);
     795           49 :         PyDict_SetItemString(pltdata, "relid", pltrelid);
     796              :         Py_DECREF(pltrelid);
     797           49 :         pfree(stroid);
     798              : 
     799           49 :         stroid = SPI_getrelname(tdata->tg_relation);
     800           49 :         plttablename = PLyUnicode_FromString(stroid);
     801           49 :         PyDict_SetItemString(pltdata, "table_name", plttablename);
     802              :         Py_DECREF(plttablename);
     803           49 :         pfree(stroid);
     804              : 
     805           49 :         stroid = SPI_getnspname(tdata->tg_relation);
     806           49 :         plttableschema = PLyUnicode_FromString(stroid);
     807           49 :         PyDict_SetItemString(pltdata, "table_schema", plttableschema);
     808              :         Py_DECREF(plttableschema);
     809           49 :         pfree(stroid);
     810              : 
     811           49 :         if (TRIGGER_FIRED_BEFORE(tdata->tg_event))
     812           36 :             pltwhen = PLyUnicode_FromString("BEFORE");
     813           13 :         else if (TRIGGER_FIRED_AFTER(tdata->tg_event))
     814           10 :             pltwhen = PLyUnicode_FromString("AFTER");
     815            3 :         else if (TRIGGER_FIRED_INSTEAD(tdata->tg_event))
     816            3 :             pltwhen = PLyUnicode_FromString("INSTEAD OF");
     817              :         else
     818              :         {
     819            0 :             elog(ERROR, "unrecognized WHEN tg_event: %u", tdata->tg_event);
     820              :             pltwhen = NULL;     /* keep compiler quiet */
     821              :         }
     822           49 :         PyDict_SetItemString(pltdata, "when", pltwhen);
     823              :         Py_DECREF(pltwhen);
     824              : 
     825           49 :         if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
     826              :         {
     827           44 :             pltlevel = PLyUnicode_FromString("ROW");
     828           44 :             PyDict_SetItemString(pltdata, "level", pltlevel);
     829              :             Py_DECREF(pltlevel);
     830              : 
     831              :             /*
     832              :              * Note: In BEFORE trigger, stored generated columns are not
     833              :              * computed yet, so don't make them accessible in NEW row.
     834              :              */
     835              : 
     836           44 :             if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
     837              :             {
     838           21 :                 pltevent = PLyUnicode_FromString("INSERT");
     839              : 
     840           21 :                 PyDict_SetItemString(pltdata, "old", Py_None);
     841           42 :                 pytnew = PLy_input_from_tuple(&proc->result_in,
     842              :                                               tdata->tg_trigtuple,
     843              :                                               rel_descr,
     844           21 :                                               !TRIGGER_FIRED_BEFORE(tdata->tg_event));
     845           21 :                 PyDict_SetItemString(pltdata, "new", pytnew);
     846              :                 Py_DECREF(pytnew);
     847           21 :                 *rv = tdata->tg_trigtuple;
     848              :             }
     849           23 :             else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
     850              :             {
     851            6 :                 pltevent = PLyUnicode_FromString("DELETE");
     852              : 
     853            6 :                 PyDict_SetItemString(pltdata, "new", Py_None);
     854            6 :                 pytold = PLy_input_from_tuple(&proc->result_in,
     855              :                                               tdata->tg_trigtuple,
     856              :                                               rel_descr,
     857              :                                               true);
     858            6 :                 PyDict_SetItemString(pltdata, "old", pytold);
     859              :                 Py_DECREF(pytold);
     860            6 :                 *rv = tdata->tg_trigtuple;
     861              :             }
     862           17 :             else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
     863              :             {
     864           17 :                 pltevent = PLyUnicode_FromString("UPDATE");
     865              : 
     866           34 :                 pytnew = PLy_input_from_tuple(&proc->result_in,
     867              :                                               tdata->tg_newtuple,
     868              :                                               rel_descr,
     869           17 :                                               !TRIGGER_FIRED_BEFORE(tdata->tg_event));
     870           17 :                 PyDict_SetItemString(pltdata, "new", pytnew);
     871              :                 Py_DECREF(pytnew);
     872           17 :                 pytold = PLy_input_from_tuple(&proc->result_in,
     873              :                                               tdata->tg_trigtuple,
     874              :                                               rel_descr,
     875              :                                               true);
     876           17 :                 PyDict_SetItemString(pltdata, "old", pytold);
     877              :                 Py_DECREF(pytold);
     878           17 :                 *rv = tdata->tg_newtuple;
     879              :             }
     880              :             else
     881              :             {
     882            0 :                 elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
     883              :                 pltevent = NULL;    /* keep compiler quiet */
     884              :             }
     885              : 
     886           44 :             PyDict_SetItemString(pltdata, "event", pltevent);
     887              :             Py_DECREF(pltevent);
     888              :         }
     889            5 :         else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))
     890              :         {
     891            5 :             pltlevel = PLyUnicode_FromString("STATEMENT");
     892            5 :             PyDict_SetItemString(pltdata, "level", pltlevel);
     893              :             Py_DECREF(pltlevel);
     894              : 
     895            5 :             PyDict_SetItemString(pltdata, "old", Py_None);
     896            5 :             PyDict_SetItemString(pltdata, "new", Py_None);
     897            5 :             *rv = NULL;
     898              : 
     899            5 :             if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
     900            1 :                 pltevent = PLyUnicode_FromString("INSERT");
     901            4 :             else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
     902            1 :                 pltevent = PLyUnicode_FromString("DELETE");
     903            3 :             else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
     904            2 :                 pltevent = PLyUnicode_FromString("UPDATE");
     905            1 :             else if (TRIGGER_FIRED_BY_TRUNCATE(tdata->tg_event))
     906            1 :                 pltevent = PLyUnicode_FromString("TRUNCATE");
     907              :             else
     908              :             {
     909            0 :                 elog(ERROR, "unrecognized OP tg_event: %u", tdata->tg_event);
     910              :                 pltevent = NULL;    /* keep compiler quiet */
     911              :             }
     912              : 
     913            5 :             PyDict_SetItemString(pltdata, "event", pltevent);
     914              :             Py_DECREF(pltevent);
     915              :         }
     916              :         else
     917            0 :             elog(ERROR, "unrecognized LEVEL tg_event: %u", tdata->tg_event);
     918              : 
     919           49 :         if (tdata->tg_trigger->tgnargs)
     920              :         {
     921              :             /*
     922              :              * all strings...
     923              :              */
     924              :             int         i;
     925              :             PyObject   *pltarg;
     926              : 
     927              :             /* pltargs should have been allocated before the PG_TRY block. */
     928              :             Assert(pltargs && pltargs != Py_None);
     929              : 
     930           45 :             for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
     931              :             {
     932           29 :                 pltarg = PLyUnicode_FromString(tdata->tg_trigger->tgargs[i]);
     933              : 
     934              :                 /*
     935              :                  * stolen, don't Py_DECREF
     936              :                  */
     937           29 :                 PyList_SetItem(pltargs, i, pltarg);
     938              :             }
     939              :         }
     940              :         else
     941              :         {
     942              :             Assert(pltargs == Py_None);
     943              :         }
     944           49 :         PyDict_SetItemString(pltdata, "args", pltargs);
     945              :         Py_DECREF(pltargs);
     946              :     }
     947            0 :     PG_CATCH();
     948              :     {
     949            0 :         Py_XDECREF(pltargs);
     950            0 :         Py_XDECREF(pltdata);
     951            0 :         PG_RE_THROW();
     952              :     }
     953           49 :     PG_END_TRY();
     954              : 
     955           49 :     return pltdata;
     956              : }
     957              : 
     958              : /*
     959              :  * Apply changes requested by a MODIFY return from a trigger function.
     960              :  */
     961              : static HeapTuple
     962           20 : PLy_modify_tuple(PLyProcedure *proc, PyObject *pltd, TriggerData *tdata,
     963              :                  HeapTuple otup)
     964              : {
     965              :     HeapTuple   rtup;
     966              :     PyObject   *volatile plntup;
     967              :     PyObject   *volatile plkeys;
     968              :     PyObject   *volatile plval;
     969              :     Datum      *volatile modvalues;
     970              :     bool       *volatile modnulls;
     971              :     bool       *volatile modrepls;
     972              :     ErrorContextCallback plerrcontext;
     973              : 
     974           20 :     plerrcontext.callback = plpython_trigger_error_callback;
     975           20 :     plerrcontext.previous = error_context_stack;
     976           20 :     error_context_stack = &plerrcontext;
     977              : 
     978           20 :     plntup = plkeys = plval = NULL;
     979           20 :     modvalues = NULL;
     980           20 :     modnulls = NULL;
     981           20 :     modrepls = NULL;
     982              : 
     983           20 :     PG_TRY();
     984              :     {
     985              :         TupleDesc   tupdesc;
     986              :         int         nkeys,
     987              :                     i;
     988              : 
     989           20 :         if ((plntup = PyDict_GetItemString(pltd, "new")) == NULL)
     990            1 :             ereport(ERROR,
     991              :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     992              :                      errmsg("TD[\"new\"] deleted, cannot modify row")));
     993           19 :         Py_INCREF(plntup);
     994           19 :         if (!PyDict_Check(plntup))
     995            1 :             ereport(ERROR,
     996              :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
     997              :                      errmsg("TD[\"new\"] is not a dictionary")));
     998              : 
     999           18 :         plkeys = PyDict_Keys(plntup);
    1000           18 :         nkeys = PyList_Size(plkeys);
    1001              : 
    1002           18 :         tupdesc = RelationGetDescr(tdata->tg_relation);
    1003              : 
    1004           18 :         modvalues = (Datum *) palloc0(tupdesc->natts * sizeof(Datum));
    1005           18 :         modnulls = (bool *) palloc0(tupdesc->natts * sizeof(bool));
    1006           18 :         modrepls = (bool *) palloc0(tupdesc->natts * sizeof(bool));
    1007              : 
    1008           45 :         for (i = 0; i < nkeys; i++)
    1009              :         {
    1010              :             PyObject   *platt;
    1011              :             char       *plattstr;
    1012              :             int         attn;
    1013              :             PLyObToDatum *att;
    1014              : 
    1015           31 :             platt = PyList_GetItem(plkeys, i);
    1016           31 :             if (PyUnicode_Check(platt))
    1017           30 :                 plattstr = PLyUnicode_AsString(platt);
    1018              :             else
    1019              :             {
    1020            1 :                 ereport(ERROR,
    1021              :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    1022              :                          errmsg("TD[\"new\"] dictionary key at ordinal position %d is not a string", i)));
    1023              :                 plattstr = NULL;    /* keep compiler quiet */
    1024              :             }
    1025           30 :             attn = SPI_fnumber(tupdesc, plattstr);
    1026           30 :             if (attn == SPI_ERROR_NOATTRIBUTE)
    1027            2 :                 ereport(ERROR,
    1028              :                         (errcode(ERRCODE_UNDEFINED_COLUMN),
    1029              :                          errmsg("key \"%s\" found in TD[\"new\"] does not exist as a column in the triggering row",
    1030              :                                 plattstr)));
    1031           28 :             if (attn <= 0)
    1032            0 :                 ereport(ERROR,
    1033              :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1034              :                          errmsg("cannot set system attribute \"%s\"",
    1035              :                                 plattstr)));
    1036           28 :             if (TupleDescAttr(tupdesc, attn - 1)->attgenerated)
    1037            1 :                 ereport(ERROR,
    1038              :                         (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
    1039              :                          errmsg("cannot set generated column \"%s\"",
    1040              :                                 plattstr)));
    1041              : 
    1042           27 :             plval = PyDict_GetItem(plntup, platt);
    1043           27 :             if (plval == NULL)
    1044            0 :                 elog(FATAL, "Python interpreter is probably corrupted");
    1045              : 
    1046           27 :             Py_INCREF(plval);
    1047              : 
    1048              :             /* We assume proc->result is set up to convert tuples properly */
    1049           27 :             att = &proc->result.tuple.atts[attn - 1];
    1050              : 
    1051           54 :             modvalues[attn - 1] = PLy_output_convert(att,
    1052              :                                                      plval,
    1053           27 :                                                      &modnulls[attn - 1]);
    1054           27 :             modrepls[attn - 1] = true;
    1055              : 
    1056           27 :             Py_DECREF(plval);
    1057           27 :             plval = NULL;
    1058              :         }
    1059              : 
    1060           14 :         rtup = heap_modify_tuple(otup, tupdesc, modvalues, modnulls, modrepls);
    1061              :     }
    1062            6 :     PG_CATCH();
    1063              :     {
    1064            6 :         Py_XDECREF(plntup);
    1065            6 :         Py_XDECREF(plkeys);
    1066            6 :         Py_XDECREF(plval);
    1067              : 
    1068            6 :         if (modvalues)
    1069            4 :             pfree(modvalues);
    1070            6 :         if (modnulls)
    1071            4 :             pfree(modnulls);
    1072            6 :         if (modrepls)
    1073            4 :             pfree(modrepls);
    1074              : 
    1075            6 :         PG_RE_THROW();
    1076              :     }
    1077           14 :     PG_END_TRY();
    1078              : 
    1079           14 :     Py_DECREF(plntup);
    1080           14 :     Py_DECREF(plkeys);
    1081              : 
    1082           14 :     pfree(modvalues);
    1083           14 :     pfree(modnulls);
    1084           14 :     pfree(modrepls);
    1085              : 
    1086           14 :     error_context_stack = plerrcontext.previous;
    1087              : 
    1088           14 :     return rtup;
    1089              : }
    1090              : 
    1091              : static void
    1092            6 : plpython_trigger_error_callback(void *arg)
    1093              : {
    1094            6 :     PLyExecutionContext *exec_ctx = PLy_current_execution_context();
    1095              : 
    1096            6 :     if (exec_ctx->curr_proc)
    1097            6 :         errcontext("while modifying trigger row");
    1098            6 : }
    1099              : 
    1100              : /* execute Python code, propagate Python errors to the backend */
    1101              : static PyObject *
    1102          572 : PLy_procedure_call(PLyProcedure *proc, const char *kargs, PyObject *vargs)
    1103              : {
    1104          572 :     PyObject   *rv = NULL;
    1105          572 :     int volatile save_subxact_level = list_length(explicit_subtransactions);
    1106              : 
    1107          572 :     PyDict_SetItemString(proc->globals, kargs, vargs);
    1108              : 
    1109          572 :     PG_TRY();
    1110              :     {
    1111          572 :         rv = PyEval_EvalCode(proc->code, proc->globals, proc->globals);
    1112              : 
    1113              :         /*
    1114              :          * Since plpy will only let you close subtransactions that you
    1115              :          * started, you cannot *unnest* subtransactions, only *nest* them
    1116              :          * without closing.
    1117              :          */
    1118              :         Assert(list_length(explicit_subtransactions) >= save_subxact_level);
    1119              :     }
    1120            0 :     PG_FINALLY();
    1121              :     {
    1122          572 :         PLy_abort_open_subtransactions(save_subxact_level);
    1123              :     }
    1124          572 :     PG_END_TRY();
    1125              : 
    1126              :     /* If the Python code returned an error, propagate it */
    1127          572 :     if (rv == NULL)
    1128           54 :         PLy_elog(ERROR, NULL);
    1129              : 
    1130          518 :     return rv;
    1131              : }
    1132              : 
    1133              : /*
    1134              :  * Abort lingering subtransactions that have been explicitly started
    1135              :  * by plpy.subtransaction().start() and not properly closed.
    1136              :  */
    1137              : static void
    1138          572 : PLy_abort_open_subtransactions(int save_subxact_level)
    1139              : {
    1140              :     Assert(save_subxact_level >= 0);
    1141              : 
    1142          578 :     while (list_length(explicit_subtransactions) > save_subxact_level)
    1143              :     {
    1144              :         PLySubtransactionData *subtransactiondata;
    1145              : 
    1146              :         Assert(explicit_subtransactions != NIL);
    1147              : 
    1148            6 :         ereport(WARNING,
    1149              :                 (errmsg("forcibly aborting a subtransaction that has not been exited")));
    1150              : 
    1151            6 :         RollbackAndReleaseCurrentSubTransaction();
    1152              : 
    1153            6 :         subtransactiondata = (PLySubtransactionData *) linitial(explicit_subtransactions);
    1154            6 :         explicit_subtransactions = list_delete_first(explicit_subtransactions);
    1155              : 
    1156            6 :         MemoryContextSwitchTo(subtransactiondata->oldcontext);
    1157            6 :         CurrentResourceOwner = subtransactiondata->oldowner;
    1158            6 :         pfree(subtransactiondata);
    1159              :     }
    1160          572 : }
        

Generated by: LCOV version 2.0-1