LCOV - differential code coverage report
Current view: top level - src/pl/plpython - plpy_main.c (source / functions) Coverage Total Hit UNC UBC GNC CBC DCB
Current: c38de3ae6098ccf1904109f2e550eb4777f66024 vs e352ac8c5c90ed6ce792f044c22145578542a330 Lines: 93.5 % 184 172 2 10 14 158 2
Current Date: 2026-11-05 14:14:01 +0100 Functions: 100.0 % 15 15 1 14
Baseline: lcov-20261105-baseline Branches: 66.5 % 179 119 8 52 22 97
Baseline Date: 2026-11-05 14:14:01 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(1,7] days: 87.5 % 16 14 2 14
(30,360] days: 88.6 % 44 39 5 39
(360..) days: 96.0 % 124 119 5 119
Function coverage date bins:
(360..) days: 100.0 % 15 15 1 14
Branch coverage date bins:
(1,7] days: 73.3 % 30 22 8 22
(30,360] days: 60.3 % 68 41 27 41
(360..) days: 69.1 % 81 56 25 56

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*
                                  2                 :                :  * PL/Python main entry points
                                  3                 :                :  *
                                  4                 :                :  * src/pl/plpython/plpy_main.c
                                  5                 :                :  */
                                  6                 :                : 
                                  7                 :                : #include "postgres.h"
                                  8                 :                : 
                                  9                 :                : #include "catalog/pg_proc.h"
                                 10                 :                : #include "commands/event_trigger.h"
                                 11                 :                : #include "commands/trigger.h"
                                 12                 :                : #include "executor/spi.h"
                                 13                 :                : #include "funcapi.h"
                                 14                 :                : #include "miscadmin.h"
                                 15                 :                : #include "plpy_elog.h"
                                 16                 :                : #include "plpy_exec.h"
                                 17                 :                : #include "plpy_main.h"
                                 18                 :                : #include "plpy_plpymodule.h"
                                 19                 :                : #include "plpy_subxactobject.h"
                                 20                 :                : #include "plpy_util.h"
                                 21                 :                : #include "utils/builtins.h"
                                 22                 :                : #include "utils/guc.h"
                                 23                 :                : #include "utils/lsyscache.h"
                                 24                 :                : #include "utils/memutils.h"
                                 25                 :                : #include "utils/syscache.h"
                                 26                 :                : 
                                 27                 :                : /*
                                 28                 :                :  * exported functions
                                 29                 :                :  */
                                 30                 :                : 
  589 tgl@sss.pgh.pa.us          31                 :CBC          23 : PG_MODULE_MAGIC_EXT(
                                 32                 :                :                     .name = "plpython",
                                 33                 :                :                     .version = PG_VERSION
                                 34                 :                : );
                                 35                 :                : 
 1704 andres@anarazel.de         36                 :             26 : PG_FUNCTION_INFO_V1(plpython3_validator);
                                 37                 :             26 : PG_FUNCTION_INFO_V1(plpython3_call_handler);
                                 38                 :              8 : PG_FUNCTION_INFO_V1(plpython3_inline_handler);
                                 39                 :                : 
                                 40                 :                : 
                                 41                 :                : static PLyTrigType PLy_procedure_is_trigger(Form_pg_proc procStruct);
                                 42                 :                : static void plpython_error_callback(void *arg);
                                 43                 :                : static void plpython_inline_error_callback(void *arg);
                                 44                 :                : 
                                 45                 :                : static PLyExecutionContext *PLy_push_execution_context(bool atomic_context);
                                 46                 :                : static void PLy_pop_execution_context(void);
                                 47                 :                : 
                                 48                 :                : /* initialize global variables */
                                 49                 :                : PyObject   *PLy_interp_globals = NULL;
                                 50                 :                : 
                                 51                 :                : /* this doesn't need to be global; use PLy_current_execution_context() */
                                 52                 :                : static PLyExecutionContext *PLy_execution_contexts = NULL;
                                 53                 :                : 
                                 54                 :                : 
                                 55                 :                : void
 5436 peter_e@gmx.net            56                 :             23 : _PG_init(void)
                                 57                 :                : {
                                 58                 :                :     PyObject   *main_mod;
                                 59                 :                :     PyObject   *main_dict;
                                 60                 :                :     PyObject   *GD;
                                 61                 :                :     PyObject   *plpy_mod;
                                 62                 :                : 
  294 peter@eisentraut.org       63                 :             23 :     pg_bindtextdomain(TEXTDOMAIN);
                                 64                 :                : 
                                 65                 :                :     /* Add plpy to table of built-in modules. */
 5436 peter_e@gmx.net            66                 :             23 :     PyImport_AppendInittab("plpy", PyInit_plpy);
                                 67                 :                : 
                                 68                 :                :     /* Initialize Python interpreter. */
                                 69                 :             23 :     Py_Initialize();
                                 70                 :                : 
  294 peter@eisentraut.org       71                 :             23 :     main_mod = PyImport_AddModule("__main__");
                                 72   [ +  -  -  + ]:             23 :     if (main_mod == NULL || PyErr_Occurred())
  294 peter@eisentraut.org       73                 :UBC           0 :         PLy_elog(ERROR, "could not import \"%s\" module", "__main__");
                                 74                 :                :     Py_INCREF(main_mod);
                                 75                 :                : 
  294 peter@eisentraut.org       76                 :CBC          23 :     main_dict = PyModule_GetDict(main_mod);
                                 77         [ -  + ]:             23 :     if (main_dict == NULL)
  294 peter@eisentraut.org       78                 :UBC           0 :         PLy_elog(ERROR, NULL);
                                 79                 :                : 
                                 80                 :                :     /*
                                 81                 :                :      * Set up GD.
                                 82                 :                :      */
  294 peter@eisentraut.org       83                 :CBC          23 :     GD = PyDict_New();
                                 84         [ -  + ]:             23 :     if (GD == NULL)
  294 peter@eisentraut.org       85                 :UBC           0 :         PLy_elog(ERROR, NULL);
  294 peter@eisentraut.org       86                 :CBC          23 :     PyDict_SetItemString(main_dict, "GD", GD);
                                 87                 :                : 
                                 88                 :                :     /*
                                 89                 :                :      * Import plpy.
                                 90                 :                :      */
                                 91                 :             23 :     plpy_mod = PyImport_ImportModule("plpy");
                                 92         [ -  + ]:             23 :     if (plpy_mod == NULL)
  294 peter@eisentraut.org       93                 :UBC           0 :         PLy_elog(ERROR, "could not import \"%s\" module", "plpy");
  294 peter@eisentraut.org       94         [ -  + ]:CBC          23 :     if (PyDict_SetItemString(main_dict, "plpy", plpy_mod) == -1)
  294 peter@eisentraut.org       95                 :UBC           0 :         PLy_elog(ERROR, NULL);
                                 96                 :                : 
 5436 peter_e@gmx.net            97         [ -  + ]:CBC          23 :     if (PyErr_Occurred())
 5436 peter_e@gmx.net            98                 :UBC           0 :         PLy_elog(FATAL, "untrapped error in initialization");
                                 99                 :                : 
                                100                 :                :     Py_INCREF(main_dict);
  294 peter@eisentraut.org      101                 :CBC          23 :     PLy_interp_globals = main_dict;
                                102                 :                : 
                                103                 :                :     Py_DECREF(main_mod);
                                104                 :                : 
 5436 peter_e@gmx.net           105                 :             23 :     explicit_subtransactions = NIL;
                                106                 :                : 
 5350 tgl@sss.pgh.pa.us         107                 :             23 :     PLy_execution_contexts = NULL;
 5436 peter_e@gmx.net           108                 :             23 : }
                                109                 :                : 
                                110                 :                : Datum
 1704 andres@anarazel.de        111                 :            272 : plpython3_validator(PG_FUNCTION_ARGS)
                                112                 :                : {
  137 tgl@sss.pgh.pa.us         113                 :            272 :     LOCAL_FCINFO(fake_fcinfo, 0);
 5436 peter_e@gmx.net           114                 :            272 :     Oid         funcoid = PG_GETARG_OID(0);
                                115                 :                :     HeapTuple   tuple;
                                116                 :                :     Form_pg_proc procStruct;
                                117                 :                :     Oid         rettype;
                                118                 :                :     Oid        *argtypes;
                                119                 :                :     char      **argnames,
                                120                 :                :                *argmodes;
                                121                 :                :     int         nargs;
                                122                 :                :     PLyTrigType is_trigger;
                                123                 :                :     TriggerData trigdata;
                                124                 :                :     EventTriggerData etrigdata;
                                125                 :                :     FmgrInfo    flinfo;
                                126                 :                :     PLyProcedureCache *pcache;
                                127                 :                : 
 4644 noah@leadboat.com         128         [ -  + ]:            272 :     if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
 4644 noah@leadboat.com         129                 :UBC           0 :         PG_RETURN_VOID();
                                130                 :                : 
                                131                 :                :     /* Get the new function's pg_proc entry */
 5436 peter_e@gmx.net           132                 :CBC         272 :     tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
                                133         [ -  + ]:            272 :     if (!HeapTupleIsValid(tuple))
 5436 peter_e@gmx.net           134         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for function %u", funcoid);
 5436 peter_e@gmx.net           135                 :CBC         272 :     procStruct = (Form_pg_proc) GETSTRUCT(tuple);
                                136                 :                : 
                                137                 :                :     /* Disallow pseudotype result, except for void or record */
    4 tgl@sss.pgh.pa.us         138                 :GNC         272 :     rettype = procStruct->prorettype;
                                139         [ +  + ]:            272 :     if (get_typtype(rettype) == TYPTYPE_PSEUDO)
                                140                 :                :     {
                                141   [ +  +  +  + ]:             83 :         if (rettype == VOIDOID || rettype == RECORDOID)
                                142                 :                :              /* okay */ ;
                                143   [ +  +  +  + ]:             26 :         else if (rettype == TRIGGEROID || rettype == EVENT_TRIGGEROID)
                                144                 :                :              /* okay */ ;
                                145                 :                :         else
                                146         [ +  - ]:              1 :             ereport(ERROR,
                                147                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                148                 :                :                      errmsg("PL/Python functions cannot return type %s",
                                149                 :                :                             format_type_be(rettype))));
                                150                 :                :     }
                                151                 :                : 
                                152                 :                :     /* Disallow pseudotype arguments, except for output records */
                                153                 :            271 :     nargs = get_func_arg_info(tuple, &argtypes, &argnames, &argmodes);
                                154         [ +  + ]:            462 :     for (int i = 0; i < nargs; i++)
                                155                 :                :     {
                                156         [ +  + ]:            192 :         if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
                                157                 :                :         {
                                158         [ +  + ]:              3 :             if (argmodes &&
                                159         [ -  + ]:              2 :                 (argmodes[i] == PROARGMODE_OUT ||
    4 tgl@sss.pgh.pa.us         160         [ #  # ]:UNC           0 :                  argmodes[i] == PROARGMODE_TABLE))
                                161                 :                :             {
    4 tgl@sss.pgh.pa.us         162         [ -  + ]:GNC           2 :                 if (rettype == RECORDOID)
                                163                 :                :                      /* okay */ ;
                                164                 :                :                 else
    4 tgl@sss.pgh.pa.us         165         [ #  # ]:UNC           0 :                     ereport(ERROR,
                                166                 :                :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                167                 :                :                              errmsg("PL/Python functions cannot return type %s",
                                168                 :                :                                     format_type_be(argtypes[i]))));
                                169                 :                :             }
                                170                 :                :             else
    4 tgl@sss.pgh.pa.us         171         [ +  - ]:GNC           1 :                 ereport(ERROR,
                                172                 :                :                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                173                 :                :                          errmsg("PL/Python functions cannot accept type %s",
                                174                 :                :                                 format_type_be(argtypes[i]))));
                                175                 :                :         }
                                176                 :                :     }
                                177                 :                : 
 5436 peter_e@gmx.net           178                 :CBC         270 :     is_trigger = PLy_procedure_is_trigger(procStruct);
                                179                 :                : 
                                180                 :            270 :     ReleaseSysCache(tuple);
                                181                 :                : 
                                182                 :                :     /* The rest is not needed/wanted if check_function_bodies is off */
    4 tgl@sss.pgh.pa.us         183         [ +  + ]:GNC         270 :     if (!check_function_bodies)
                                184                 :              1 :         PG_RETURN_VOID();
                                185                 :                : 
                                186                 :                :     /*
                                187                 :                :      * Set up a fake flinfo/fcinfo with just enough info to satisfy
                                188                 :                :      * PLy_procedure_get().  That function derives the call context (plain
                                189                 :                :      * function, DML trigger, or event trigger) from the fcinfo, so we have to
                                190                 :                :      * construct matching context here.
                                191                 :                :      */
  137 tgl@sss.pgh.pa.us         192   [ +  -  +  -  :CBC        1345 :     MemSet(fake_fcinfo, 0, SizeForFunctionCallInfo(0));
                                     +  -  +  -  +  
                                                 + ]
                                193   [ +  -  +  -  :           1883 :     MemSet(&flinfo, 0, sizeof(flinfo));
                                     +  -  +  -  +  
                                                 + ]
                                194                 :            269 :     fake_fcinfo->flinfo = &flinfo;
                                195                 :            269 :     flinfo.fn_oid = funcoid;
                                196                 :            269 :     flinfo.fn_mcxt = CurrentMemoryContext;
                                197                 :                : 
                                198         [ +  + ]:            269 :     if (is_trigger == PLPY_TRIGGER)
                                199                 :                :     {
                                200   [ +  -  +  -  :            264 :         MemSet(&trigdata, 0, sizeof(trigdata));
                                     +  -  +  -  +  
                                                 + ]
                                201                 :             24 :         trigdata.type = T_TriggerData;
                                202                 :                :         /* We can't validate triggers against any particular table ... */
                                203                 :             24 :         fake_fcinfo->context = (Node *) &trigdata;
                                204                 :                :     }
                                205         [ +  + ]:            245 :     else if (is_trigger == PLPY_EVENT_TRIGGER)
                                206                 :                :     {
                                207   [ +  -  +  -  :              5 :         MemSet(&etrigdata, 0, sizeof(etrigdata));
                                     +  -  +  -  +  
                                                 + ]
                                208                 :              1 :         etrigdata.type = T_EventTriggerData;
                                209                 :              1 :         fake_fcinfo->context = (Node *) &etrigdata;
                                210                 :                :     }
                                211                 :                : 
                                212                 :            269 :     pcache = PLy_procedure_get(fake_fcinfo, true);
                                213                 :                : 
                                214                 :                :     /*
                                215                 :                :      * Release the reference count that PLy_procedure_get acquired; the
                                216                 :                :      * PLyProcedure object remains valid for possible future use.  (We could
                                217                 :                :      * leave this to be done when the calling memory context is cleaned up,
                                218                 :                :      * but it seems neater to do it right away.  Note we mustn't release the
                                219                 :                :      * pcache object, since the memory-context reset callback has a reference
                                220                 :                :      * to it.)
                                221                 :                :      */
                                222         [ -  + ]:            268 :     Assert(pcache->proc->cfunc.use_count > 0);
                                223                 :            268 :     pcache->proc->cfunc.use_count--;
                                224                 :            268 :     pcache->proc = NULL;
                                225                 :                : 
 5436 peter_e@gmx.net           226                 :            268 :     PG_RETURN_VOID();
                                227                 :                : }
                                228                 :                : 
                                229                 :                : Datum
 1704 andres@anarazel.de        230                 :            731 : plpython3_call_handler(PG_FUNCTION_ARGS)
                                231                 :                : {
                                232                 :                :     bool        nonatomic;
                                233                 :                :     Datum       retval;
                                234                 :                :     PLyExecutionContext *exec_ctx;
                                235                 :                :     ErrorContextCallback plerrcontext;
                                236                 :                : 
 3209 peter_e@gmx.net           237                 :           1529 :     nonatomic = fcinfo->context &&
                                238   [ +  +  +  + ]:            739 :         IsA(fcinfo->context, CallContext) &&
                                239         [ +  + ]:              8 :         !castNode(CallContext, fcinfo->context)->atomic;
                                240                 :                : 
                                241                 :                :     /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
  787 tgl@sss.pgh.pa.us         242                 :            731 :     SPI_connect_ext(nonatomic ? SPI_OPT_NONATOMIC : 0);
                                243                 :                : 
                                244                 :                :     /*
                                245                 :                :      * Push execution context onto stack.  It is important that this get
                                246                 :                :      * popped again, so avoid putting anything that could throw error between
                                247                 :                :      * here and the PG_TRY.
                                248                 :                :      */
 3209 peter_e@gmx.net           249                 :            731 :     exec_ctx = PLy_push_execution_context(!nonatomic);
                                250                 :                : 
 5436                           251         [ +  + ]:            731 :     PG_TRY();
                                252                 :                :     {
                                253                 :                :         PLyProcedureCache *pcache;
                                254                 :                : 
                                255                 :                :         /*
                                256                 :                :          * Setup error traceback support for ereport().  Note that the PG_TRY
                                257                 :                :          * structure pops this for us again at exit, so we needn't do that
                                258                 :                :          * explicitly, nor do we risk the callback getting called after we've
                                259                 :                :          * destroyed the exec_ctx.
                                260                 :                :          */
 3186 tgl@sss.pgh.pa.us         261                 :            731 :         plerrcontext.callback = plpython_error_callback;
                                262                 :            731 :         plerrcontext.arg = exec_ctx;
                                263                 :            731 :         plerrcontext.previous = error_context_stack;
                                264                 :            731 :         error_context_stack = &plerrcontext;
                                265                 :                : 
                                266                 :                :         /*
                                267                 :                :          * Look up (and if necessary compile) the procedure.  This can throw
                                268                 :                :          * an error, so it must happen inside the PG_TRY so that the execution
                                269                 :                :          * context gets popped on the way out.
                                270                 :                :          */
  137                           271                 :            731 :         pcache = PLy_procedure_get(fcinfo, false);
                                272                 :            728 :         exec_ctx->curr_proc = pcache->proc;
                                273                 :                : 
 5436 peter_e@gmx.net           274   [ +  +  +  + ]:            728 :         if (CALLED_AS_TRIGGER(fcinfo))
                                275                 :             40 :         {
                                276                 :                :             HeapTuple   trv;
                                277                 :                : 
  137 tgl@sss.pgh.pa.us         278                 :             49 :             trv = PLy_exec_trigger(fcinfo, pcache->proc);
 5436 peter_e@gmx.net           279                 :             40 :             retval = PointerGetDatum(trv);
                                280                 :                :         }
  441 peter@eisentraut.org      281   [ +  +  +  + ]:            679 :         else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
                                282                 :                :         {
  137 tgl@sss.pgh.pa.us         283                 :             10 :             PLy_exec_event_trigger(fcinfo, pcache->proc);
  441 peter@eisentraut.org      284                 :             10 :             retval = (Datum) 0;
                                285                 :                :         }
                                286                 :                :         else
  137 tgl@sss.pgh.pa.us         287                 :            669 :             retval = PLy_exec_function(fcinfo, pcache);
                                288                 :                :     }
 5436 peter_e@gmx.net           289                 :            108 :     PG_CATCH();
                                290                 :                :     {
                                291                 :                :         /* Destroy the execution context */
 5350 tgl@sss.pgh.pa.us         292                 :            108 :         PLy_pop_execution_context();
 5436 peter_e@gmx.net           293                 :            108 :         PyErr_Clear();
                                294                 :                : 
                                295                 :            108 :         PG_RE_THROW();
                                296                 :                :     }
                                297         [ -  + ]:            623 :     PG_END_TRY();
                                298                 :                : 
                                299                 :                :     /* Destroy the execution context */
 5350 tgl@sss.pgh.pa.us         300                 :            623 :     PLy_pop_execution_context();
                                301                 :                : 
 5436 peter_e@gmx.net           302                 :            623 :     return retval;
                                303                 :                : }
                                304                 :                : 
                                305                 :                : Datum
 1704 andres@anarazel.de        306                 :             21 : plpython3_inline_handler(PG_FUNCTION_ARGS)
                                307                 :                : {
 2840                           308                 :             21 :     LOCAL_FCINFO(fake_fcinfo, 0);
 5436 peter_e@gmx.net           309                 :             21 :     InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
                                310                 :                :     FmgrInfo    flinfo;
                                311                 :                :     PLyProcedure proc;
                                312                 :                :     PLyProcedureCache pcache;
                                313                 :                :     PLyExecutionContext *exec_ctx;
                                314                 :                :     ErrorContextCallback plerrcontext;
                                315                 :                : 
                                316                 :                :     /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
  787 tgl@sss.pgh.pa.us         317                 :             21 :     SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC);
                                318                 :                : 
 2840 andres@anarazel.de        319   [ +  -  +  -  :            105 :     MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
                                     +  -  +  -  +  
                                                 + ]
 5436 peter_e@gmx.net           320   [ +  -  +  -  :            147 :     MemSet(&flinfo, 0, sizeof(flinfo));
                                     +  -  +  -  +  
                                                 + ]
 2840 andres@anarazel.de        321                 :             21 :     fake_fcinfo->flinfo = &flinfo;
 5436 peter_e@gmx.net           322                 :             21 :     flinfo.fn_oid = InvalidOid;
                                323                 :             21 :     flinfo.fn_mcxt = CurrentMemoryContext;
                                324                 :                : 
                                325   [ +  -  +  -  :            945 :     MemSet(&proc, 0, sizeof(PLyProcedure));
                                     +  -  +  -  +  
                                                 + ]
 4018 tgl@sss.pgh.pa.us         326                 :             21 :     proc.mcxt = AllocSetContextCreate(TopMemoryContext,
                                327                 :                :                                       "__plpython_inline_block",
                                328                 :                :                                       ALLOCSET_DEFAULT_SIZES);
                                329                 :             21 :     proc.pyname = MemoryContextStrdup(proc.mcxt, "__plpython_inline_block");
 4211 peter_e@gmx.net           330                 :             21 :     proc.langid = codeblock->langOid;
                                331                 :                : 
                                332                 :                :     /*
                                333                 :                :      * This is currently sufficient to get PLy_exec_function to work, but
                                334                 :                :      * someday we might need to be honest and use PLy_output_setup_func.
                                335                 :                :      */
 3276 tgl@sss.pgh.pa.us         336                 :             21 :     proc.result.typoid = VOIDOID;
                                337                 :                : 
                                338                 :                :     /* Set up a minimal PLyProcedureCache for the inline block */
  137                           339   [ +  -  +  -  :            168 :     MemSet(&pcache, 0, sizeof(PLyProcedureCache));
                                     +  -  +  -  +  
                                                 + ]
                                340                 :             21 :     pcache.proc = &proc;
                                341                 :             21 :     pcache.fcontext = CurrentMemoryContext;
                                342                 :                : 
                                343                 :                :     /*
                                344                 :                :      * Push execution context onto stack.  It is important that this get
                                345                 :                :      * popped again, so avoid putting anything that could throw error between
                                346                 :                :      * here and the PG_TRY.
                                347                 :                :      */
 3209 peter_e@gmx.net           348                 :             21 :     exec_ctx = PLy_push_execution_context(codeblock->atomic);
                                349                 :                : 
 5436                           350         [ +  + ]:             21 :     PG_TRY();
                                351                 :                :     {
                                352                 :                :         /*
                                353                 :                :          * Setup error traceback support for ereport().
                                354                 :                :          * plpython_inline_error_callback doesn't currently need exec_ctx, but
                                355                 :                :          * for consistency with plpython3_call_handler we do it the same way.
                                356                 :                :          */
 3186 tgl@sss.pgh.pa.us         357                 :             21 :         plerrcontext.callback = plpython_inline_error_callback;
                                358                 :             21 :         plerrcontext.arg = exec_ctx;
                                359                 :             21 :         plerrcontext.previous = error_context_stack;
                                360                 :             21 :         error_context_stack = &plerrcontext;
                                361                 :                : 
 5436 peter_e@gmx.net           362                 :             21 :         PLy_procedure_compile(&proc, codeblock->source_text);
 5350 tgl@sss.pgh.pa.us         363                 :             21 :         exec_ctx->curr_proc = &proc;
  137                           364                 :             21 :         PLy_exec_function(fake_fcinfo, &pcache);
                                365                 :                :     }
 5436 peter_e@gmx.net           366                 :             11 :     PG_CATCH();
                                367                 :                :     {
 5350 tgl@sss.pgh.pa.us         368                 :             11 :         PLy_pop_execution_context();
 5436 peter_e@gmx.net           369                 :             11 :         PLy_procedure_delete(&proc);
                                370                 :             11 :         PyErr_Clear();
                                371                 :             11 :         PG_RE_THROW();
                                372                 :                :     }
                                373         [ -  + ]:             10 :     PG_END_TRY();
                                374                 :                : 
                                375                 :                :     /* Destroy the execution context */
 5350 tgl@sss.pgh.pa.us         376                 :             10 :     PLy_pop_execution_context();
                                377                 :                : 
                                378                 :                :     /* Now clean up the transient procedure we made */
                                379                 :             10 :     PLy_procedure_delete(&proc);
                                380                 :                : 
 5436 peter_e@gmx.net           381                 :             10 :     PG_RETURN_VOID();
                                382                 :                : }
                                383                 :                : 
                                384                 :                : /*
                                385                 :                :  * Determine whether a function is a (DML or event) trigger from its pg_proc
                                386                 :                :  * result type.  This is used by the validator, which has no call context to
                                387                 :                :  * inspect; the call handler instead relies on the fcinfo's call context.
                                388                 :                :  */
                                389                 :                : static PLyTrigType
 5261 bruce@momjian.us          390                 :            270 : PLy_procedure_is_trigger(Form_pg_proc procStruct)
                                391                 :                : {
                                392                 :                :     PLyTrigType ret;
                                393                 :                : 
  441 peter@eisentraut.org      394      [ +  +  + ]:            270 :     switch (procStruct->prorettype)
                                395                 :                :     {
                                396                 :             24 :         case TRIGGEROID:
                                397                 :             24 :             ret = PLPY_TRIGGER;
                                398                 :             24 :             break;
                                399                 :              1 :         case EVENT_TRIGGEROID:
                                400                 :              1 :             ret = PLPY_EVENT_TRIGGER;
                                401                 :              1 :             break;
                                402                 :            245 :         default:
                                403                 :            245 :             ret = PLPY_NOT_TRIGGER;
                                404                 :            245 :             break;
                                405                 :                :     }
                                406                 :                : 
                                407                 :            270 :     return ret;
                                408                 :                : }
                                409                 :                : 
                                410                 :                : static void
 5436 peter_e@gmx.net           411                 :            484 : plpython_error_callback(void *arg)
                                412                 :                : {
 3186 tgl@sss.pgh.pa.us         413                 :            484 :     PLyExecutionContext *exec_ctx = (PLyExecutionContext *) arg;
                                414                 :                : 
 5350                           415         [ +  + ]:            484 :     if (exec_ctx->curr_proc)
                                416                 :                :     {
 3262 peter_e@gmx.net           417         [ +  + ]:            481 :         if (exec_ctx->curr_proc->is_procedure)
                                418                 :              4 :             errcontext("PL/Python procedure \"%s\"",
                                419                 :                :                        PLy_procedure_name(exec_ctx->curr_proc));
                                420                 :                :         else
                                421                 :            477 :             errcontext("PL/Python function \"%s\"",
                                422                 :                :                        PLy_procedure_name(exec_ctx->curr_proc));
                                423                 :                :     }
 5436                           424                 :            484 : }
                                425                 :                : 
                                426                 :                : static void
                                427                 :             28 : plpython_inline_error_callback(void *arg)
                                428                 :                : {
                                429                 :             28 :     errcontext("PL/Python anonymous code block");
                                430                 :             28 : }
                                431                 :                : 
                                432                 :                : PLyExecutionContext *
 5350 tgl@sss.pgh.pa.us         433                 :           1466 : PLy_current_execution_context(void)
                                434                 :                : {
                                435         [ -  + ]:           1466 :     if (PLy_execution_contexts == NULL)
 5350 tgl@sss.pgh.pa.us         436         [ #  # ]:UBC           0 :         elog(ERROR, "no Python function is currently executing");
                                437                 :                : 
 5350 tgl@sss.pgh.pa.us         438                 :CBC        1466 :     return PLy_execution_contexts;
                                439                 :                : }
                                440                 :                : 
                                441                 :                : MemoryContext
 4018                           442                 :            804 : PLy_get_scratch_context(PLyExecutionContext *context)
                                443                 :                : {
                                444                 :                :     /*
                                445                 :                :      * A scratch context might never be needed in a given plpython procedure,
                                446                 :                :      * so allocate it on first request.
                                447                 :                :      */
                                448         [ +  + ]:            804 :     if (context->scratch_ctx == NULL)
                                449                 :            447 :         context->scratch_ctx =
                                450                 :            447 :             AllocSetContextCreate(TopTransactionContext,
                                451                 :                :                                   "PL/Python scratch context",
                                452                 :                :                                   ALLOCSET_DEFAULT_SIZES);
                                453                 :            804 :     return context->scratch_ctx;
                                454                 :                : }
                                455                 :                : 
                                456                 :                : static PLyExecutionContext *
 3209 peter_e@gmx.net           457                 :            752 : PLy_push_execution_context(bool atomic_context)
                                458                 :                : {
                                459                 :                :     PLyExecutionContext *context;
                                460                 :                : 
                                461                 :                :     /* Pick a memory context similar to what SPI uses. */
                                462                 :                :     context = (PLyExecutionContext *)
                                463         [ +  + ]:            752 :         MemoryContextAlloc(atomic_context ? TopTransactionContext : PortalContext,
                                464                 :                :                            sizeof(PLyExecutionContext));
 5350 tgl@sss.pgh.pa.us         465                 :            752 :     context->curr_proc = NULL;
 4018                           466                 :            752 :     context->scratch_ctx = NULL;
 5350                           467                 :            752 :     context->next = PLy_execution_contexts;
                                468                 :            752 :     PLy_execution_contexts = context;
                                469                 :            752 :     return context;
                                470                 :                : }
                                471                 :                : 
                                472                 :                : static void
                                473                 :            752 : PLy_pop_execution_context(void)
                                474                 :                : {
 5261 bruce@momjian.us          475                 :            752 :     PLyExecutionContext *context = PLy_execution_contexts;
                                476                 :                : 
 5350 tgl@sss.pgh.pa.us         477         [ -  + ]:            752 :     if (context == NULL)
 5350 tgl@sss.pgh.pa.us         478         [ #  # ]:UBC           0 :         elog(ERROR, "no Python function is currently executing");
                                479                 :                : 
 5350 tgl@sss.pgh.pa.us         480                 :CBC         752 :     PLy_execution_contexts = context->next;
                                481                 :                : 
 4018                           482         [ +  + ]:            752 :     if (context->scratch_ctx)
                                483                 :            430 :         MemoryContextDelete(context->scratch_ctx);
                                484                 :            752 :     pfree(context);
 5350                           485                 :            752 : }
        

Generated by: LCOV version 2.0-1