LCOV - differential code coverage report
Current view: top level - src/pl/plpython - plpy_main.c (source / functions) Coverage Total Hit LBC UIC GBC GIC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 93.1 % 159 148 7 4 5 72 71 6 69 1
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 17 17 17 16 1
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 93.1 % 159 148 7 4 5 72 71 6 69
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 51.5 % 33 17 17 16

 Age         Owner                  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 "access/htup_details.h"
                                 10                 : #include "catalog/pg_proc.h"
                                 11                 : #include "catalog/pg_type.h"
                                 12                 : #include "commands/trigger.h"
                                 13                 : #include "executor/spi.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_procedure.h"
                                 20                 : #include "plpy_subxactobject.h"
                                 21                 : #include "plpython.h"
                                 22                 : #include "utils/guc.h"
                                 23                 : #include "utils/memutils.h"
                                 24                 : #include "utils/rel.h"
                                 25                 : #include "utils/syscache.h"
                                 26                 : 
                                 27                 : /*
                                 28                 :  * exported functions
                                 29                 :  */
                                 30                 : 
 4130 peter_e                    31 CBC          23 : PG_MODULE_MAGIC;
 4130 peter_e                    32 ECB             : 
  398 andres                     33 CBC          26 : PG_FUNCTION_INFO_V1(plpython3_validator);
  398 andres                     34 GIC          26 : PG_FUNCTION_INFO_V1(plpython3_call_handler);
                                 35               8 : PG_FUNCTION_INFO_V1(plpython3_inline_handler);
                                 36                 : 
                                 37                 : 
                                 38                 : static bool PLy_procedure_is_trigger(Form_pg_proc procStruct);
                                 39                 : static void plpython_error_callback(void *arg);
                                 40                 : static void plpython_inline_error_callback(void *arg);
                                 41                 : static void PLy_init_interp(void);
                                 42                 : 
                                 43                 : static PLyExecutionContext *PLy_push_execution_context(bool atomic_context);
                                 44                 : static void PLy_pop_execution_context(void);
                                 45                 : 
                                 46                 : /* static state for Python library conflict detection */
                                 47                 : static int *plpython_version_bitmask_ptr = NULL;
                                 48                 : static int  plpython_version_bitmask = 0;
                                 49                 : 
                                 50                 : /* initialize global variables */
                                 51                 : PyObject   *PLy_interp_globals = NULL;
                                 52                 : 
                                 53                 : /* this doesn't need to be global; use PLy_current_execution_context() */
                                 54                 : static PLyExecutionContext *PLy_execution_contexts = NULL;
                                 55                 : 
 4130 peter_e                    56 ECB             : 
                                 57                 : void
 4130 peter_e                    58 GIC          23 : _PG_init(void)
                                 59                 : {
                                 60                 :     int       **bitmask_ptr;
                                 61                 : 
                                 62                 :     /*
                                 63                 :      * Set up a shared bitmask variable telling which Python version(s) are
                                 64                 :      * loaded into this process's address space.  If there's more than one, we
                                 65                 :      * cannot call into libpython for fear of causing crashes.  But postpone
                                 66                 :      * the actual failure for later, so that operations like pg_restore can
                                 67                 :      * load more than one plpython library so long as they don't try to do
                                 68                 :      * anything much with the language.
                                 69                 :      *
                                 70                 :      * While we only support Python 3 these days, somebody might create an
                                 71                 :      * out-of-tree version adding back support for Python 2. Conflicts with
  398 andres                     72 ECB             :      * such an extension should be detected.
 2645 tgl                        73                 :      */
 2645 tgl                        74 CBC          23 :     bitmask_ptr = (int **) find_rendezvous_variable("plpython_version_bitmask");
 2645 tgl                        75 GIC          23 :     if (!(*bitmask_ptr))        /* am I the first? */
 2645 tgl                        76 CBC          23 :         *bitmask_ptr = &plpython_version_bitmask;
                                 77                 :     /* Retain pointer to the agreed-on shared variable ... */
                                 78              23 :     plpython_version_bitmask_ptr = *bitmask_ptr;
                                 79                 :     /* ... and announce my presence */
 2645 tgl                        80 GIC          23 :     *plpython_version_bitmask_ptr |= (1 << PY_MAJOR_VERSION);
                                 81                 : 
                                 82                 :     /*
                                 83                 :      * This should be safe even in the presence of conflicting plpythons, and
                                 84                 :      * it's necessary to do it before possibly throwing a conflict error, or
 2645 tgl                        85 ECB             :      * the error message won't get localized.
                                 86                 :      */
 2645 tgl                        87 GIC          23 :     pg_bindtextdomain(TEXTDOMAIN);
                                 88              23 : }
                                 89                 : 
                                 90                 : /*
                                 91                 :  * Perform one-time setup of PL/Python, after checking for a conflict
                                 92                 :  * with other versions of Python.
 2645 tgl                        93 ECB             :  */
                                 94                 : static void
 2645 tgl                        95 GIC         925 : PLy_initialize(void)
                                 96                 : {
                                 97                 :     static bool inited = false;
                                 98                 : 
                                 99                 :     /*
                                100                 :      * Check for multiple Python libraries before actively doing anything with
                                101                 :      * libpython.  This must be repeated on each entry to PL/Python, in case a
                                102                 :      * conflicting library got loaded since we last looked.
                                103                 :      *
                                104                 :      * It is attractive to weaken this error from FATAL to ERROR, but there
 2645 tgl                       105 ECB             :      * would be corner cases, so it seems best to be conservative.
 2645 tgl                       106 EUB             :      */
 2645 tgl                       107 GIC         925 :     if (*plpython_version_bitmask_ptr != (1 << PY_MAJOR_VERSION))
 2645 tgl                       108 UIC           0 :         ereport(FATAL,
                                109                 :                 (errmsg("multiple Python libraries are present in session"),
                                110                 :                  errdetail("Only one Python major version can be used in one session.")));
 2645 tgl                       111 ECB             : 
                                112                 :     /* The rest should only be done once per session */
 2645 tgl                       113 GIC         925 :     if (inited)
 2645 tgl                       114 CBC         902 :         return;
 4130 peter_e                   115 ECB             : 
 4130 peter_e                   116 CBC          23 :     PyImport_AppendInittab("plpy", PyInit_plpy);
                                117              23 :     Py_Initialize();
                                118              23 :     PyImport_ImportModule("plpy");
                                119              23 :     PLy_init_interp();
 4130 peter_e                   120 GBC          23 :     PLy_init_plpy();
 4130 peter_e                   121 GIC          23 :     if (PyErr_Occurred())
 4130 peter_e                   122 LBC           0 :         PLy_elog(FATAL, "untrapped error in initialization");
                                123                 : 
 4130 peter_e                   124 CBC          23 :     init_procedure_caches();
                                125                 : 
                                126              23 :     explicit_subtransactions = NIL;
                                127                 : 
 4044 tgl                       128              23 :     PLy_execution_contexts = NULL;
                                129                 : 
 4130 peter_e                   130 GIC          23 :     inited = true;
                                131                 : }
                                132                 : 
                                133                 : /*
                                134                 :  * This should be called only once, from PLy_initialize. Initialize the Python
                                135                 :  * interpreter and global data.
 4130 peter_e                   136 ECB             :  */
                                137                 : static void
 4130 peter_e                   138 GIC          23 : PLy_init_interp(void)
                                139                 : {
                                140                 :     static PyObject *PLy_interp_safe_globals = NULL;
 4130 peter_e                   141 ECB             :     PyObject   *mainmod;
                                142                 : 
 4130 peter_e                   143 GBC          23 :     mainmod = PyImport_AddModule("__main__");
 4130 peter_e                   144 CBC          23 :     if (mainmod == NULL || PyErr_Occurred())
 4130 peter_e                   145 LBC           0 :         PLy_elog(ERROR, "could not import \"__main__\" module");
 4130 peter_e                   146 CBC          23 :     Py_INCREF(mainmod);
                                147              23 :     PLy_interp_globals = PyModule_GetDict(mainmod);
 4130 peter_e                   148 GBC          23 :     PLy_interp_safe_globals = PyDict_New();
 4044 tgl                       149 CBC          23 :     if (PLy_interp_safe_globals == NULL)
 1986 peter_e                   150 LBC           0 :         PLy_elog(ERROR, NULL);
 4130 peter_e                   151 CBC          23 :     PyDict_SetItemString(PLy_interp_globals, "GD", PLy_interp_safe_globals);
 4130 peter_e                   152 GBC          23 :     Py_DECREF(mainmod);
 4130 peter_e                   153 CBC          23 :     if (PLy_interp_globals == NULL || PyErr_Occurred())
 4130 peter_e                   154 UIC           0 :         PLy_elog(ERROR, "could not initialize globals");
 4130 peter_e                   155 GIC          23 : }
 4130 peter_e                   156 ECB             : 
                                157                 : Datum
  398 andres                    158 CBC         237 : plpython3_validator(PG_FUNCTION_ARGS)
                                159                 : {
 4130 peter_e                   160 GIC         237 :     Oid         funcoid = PG_GETARG_OID(0);
                                161                 :     HeapTuple   tuple;
                                162                 :     Form_pg_proc procStruct;
 4130 peter_e                   163 ECB             :     bool        is_trigger;
 4130 peter_e                   164 EUB             : 
 3338 noah                      165 GIC         237 :     if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
 3338 noah                      166 LBC           0 :         PG_RETURN_VOID();
 3338 noah                      167 ECB             : 
 4130 peter_e                   168 GIC         237 :     if (!check_function_bodies)
                                169               1 :         PG_RETURN_VOID();
 2645 tgl                       170 ECB             : 
                                171                 :     /* Do this only after making sure we need to do something */
 2645 tgl                       172 GIC         236 :     PLy_initialize();
 4130 peter_e                   173 ECB             : 
                                174                 :     /* Get the new function's pg_proc entry */
 4130 peter_e                   175 GBC         236 :     tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
 4130 peter_e                   176 CBC         236 :     if (!HeapTupleIsValid(tuple))
 4130 peter_e                   177 UIC           0 :         elog(ERROR, "cache lookup failed for function %u", funcoid);
 4130 peter_e                   178 CBC         236 :     procStruct = (Form_pg_proc) GETSTRUCT(tuple);
                                179                 : 
                                180             236 :     is_trigger = PLy_procedure_is_trigger(procStruct);
                                181                 : 
 4130 peter_e                   182 GIC         236 :     ReleaseSysCache(tuple);
 4130 peter_e                   183 ECB             : 
                                184                 :     /* We can't validate triggers against any particular table ... */
 3726 tgl                       185 CBC         236 :     PLy_procedure_get(funcoid, InvalidOid, is_trigger);
                                186                 : 
 4130 peter_e                   187 GIC         235 :     PG_RETURN_VOID();
                                188                 : }
 4130 peter_e                   189 ECB             : 
                                190                 : Datum
  398 andres                    191 GIC         668 : plpython3_call_handler(PG_FUNCTION_ARGS)
                                192                 : {
                                193                 :     bool        nonatomic;
                                194                 :     Datum       retval;
                                195                 :     PLyExecutionContext *exec_ctx;
 4130 peter_e                   196 ECB             :     ErrorContextCallback plerrcontext;
                                197                 : 
 2645 tgl                       198 CBC         668 :     PLy_initialize();
 2645 tgl                       199 ECB             : 
 1903 peter_e                   200 CBC        1390 :     nonatomic = fcinfo->context &&
 1903 peter_e                   201 GIC         676 :         IsA(fcinfo->context, CallContext) &&
                                202               8 :         !castNode(CallContext, fcinfo->context)->atomic;
 1903 peter_e                   203 ECB             : 
 4044 tgl                       204 EUB             :     /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
 1903 peter_e                   205 GIC         668 :     if (SPI_connect_ext(nonatomic ? SPI_OPT_NONATOMIC : 0) != SPI_OK_CONNECT)
 4130 peter_e                   206 UIC           0 :         elog(ERROR, "SPI_connect failed");
                                207                 : 
                                208                 :     /*
                                209                 :      * Push execution context onto stack.  It is important that this get
                                210                 :      * popped again, so avoid putting anything that could throw error between
 1880 tgl                       211 ECB             :      * here and the PG_TRY.
                                212                 :      */
 1903 peter_e                   213 CBC         668 :     exec_ctx = PLy_push_execution_context(!nonatomic);
                                214                 : 
 4130                           215             668 :     PG_TRY();
                                216                 :     {
 3726 tgl                       217 GIC         668 :         Oid         funcoid = fcinfo->flinfo->fn_oid;
                                218                 :         PLyProcedure *proc;
                                219                 : 
                                220                 :         /*
                                221                 :          * Setup error traceback support for ereport().  Note that the PG_TRY
                                222                 :          * structure pops this for us again at exit, so we needn't do that
                                223                 :          * explicitly, nor do we risk the callback getting called after we've
 1880 tgl                       224 ECB             :          * destroyed the exec_ctx.
                                225                 :          */
 1880 tgl                       226 CBC         668 :         plerrcontext.callback = plpython_error_callback;
                                227             668 :         plerrcontext.arg = exec_ctx;
 1880 tgl                       228 GIC         668 :         plerrcontext.previous = error_context_stack;
 1880 tgl                       229 CBC         668 :         error_context_stack = &plerrcontext;
 1880 tgl                       230 ECB             : 
 4130 peter_e                   231 CBC         668 :         if (CALLED_AS_TRIGGER(fcinfo))
 4130 peter_e                   232 GIC          37 :         {
 3726 tgl                       233              46 :             Relation    tgrel = ((TriggerData *) fcinfo->context)->tg_relation;
 4130 peter_e                   234 ECB             :             HeapTuple   trv;
                                235                 : 
 3726 tgl                       236 CBC          46 :             proc = PLy_procedure_get(funcoid, RelationGetRelid(tgrel), true);
 4044                           237              46 :             exec_ctx->curr_proc = proc;
 4130 peter_e                   238 GIC          46 :             trv = PLy_exec_trigger(fcinfo, proc);
                                239              37 :             retval = PointerGetDatum(trv);
                                240                 :         }
 4130 peter_e                   241 ECB             :         else
                                242                 :         {
 3726 tgl                       243 CBC         622 :             proc = PLy_procedure_get(funcoid, InvalidOid, false);
 4044 tgl                       244 GIC         619 :             exec_ctx->curr_proc = proc;
 4130 peter_e                   245             619 :             retval = PLy_exec_function(fcinfo, proc);
 4130 peter_e                   246 ECB             :         }
                                247                 :     }
 4130 peter_e                   248 CBC          85 :     PG_CATCH();
 4130 peter_e                   249 ECB             :     {
 4044 tgl                       250 CBC          85 :         PLy_pop_execution_context();
 4130 peter_e                   251 GIC          85 :         PyErr_Clear();
 4130 peter_e                   252 CBC          85 :         PG_RE_THROW();
                                253                 :     }
 4130 peter_e                   254 GIC         583 :     PG_END_TRY();
 4130 peter_e                   255 ECB             : 
                                256                 :     /* Destroy the execution context */
 4044 tgl                       257 CBC         583 :     PLy_pop_execution_context();
                                258                 : 
 4130 peter_e                   259 GIC         583 :     return retval;
                                260                 : }
 4130 peter_e                   261 ECB             : 
                                262                 : Datum
  398 andres                    263 CBC          21 : plpython3_inline_handler(PG_FUNCTION_ARGS)
 4130 peter_e                   264 ECB             : {
 1534 andres                    265 GIC          21 :     LOCAL_FCINFO(fake_fcinfo, 0);
 4130 peter_e                   266              21 :     InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
                                267                 :     FmgrInfo    flinfo;
                                268                 :     PLyProcedure proc;
                                269                 :     PLyExecutionContext *exec_ctx;
 4130 peter_e                   270 ECB             :     ErrorContextCallback plerrcontext;
                                271                 : 
 2645 tgl                       272 GIC          21 :     PLy_initialize();
 2645 tgl                       273 ECB             : 
 4044 tgl                       274 EUB             :     /* Note: SPI_finish() happens in plpy_exec.c, which is dubious design */
 1903 peter_e                   275 GIC          21 :     if (SPI_connect_ext(codeblock->atomic ? 0 : SPI_OPT_NONATOMIC) != SPI_OK_CONNECT)
 4130 peter_e                   276 LBC           0 :         elog(ERROR, "SPI_connect failed");
 4130 peter_e                   277 ECB             : 
 1534 andres                    278 CBC         105 :     MemSet(fcinfo, 0, SizeForFunctionCallInfo(0));
 4130 peter_e                   279             147 :     MemSet(&flinfo, 0, sizeof(flinfo));
 1534 andres                    280              21 :     fake_fcinfo->flinfo = &flinfo;
 4130 peter_e                   281 GIC          21 :     flinfo.fn_oid = InvalidOid;
 4130 peter_e                   282 CBC          21 :     flinfo.fn_mcxt = CurrentMemoryContext;
 4130 peter_e                   283 ECB             : 
 4130 peter_e                   284 GIC         861 :     MemSet(&proc, 0, sizeof(PLyProcedure));
 2712 tgl                       285              21 :     proc.mcxt = AllocSetContextCreate(TopMemoryContext,
 2712 tgl                       286 ECB             :                                       "__plpython_inline_block",
 2416                           287                 :                                       ALLOCSET_DEFAULT_SIZES);
 2712 tgl                       288 GIC          21 :     proc.pyname = MemoryContextStrdup(proc.mcxt, "__plpython_inline_block");
 2905 peter_e                   289              21 :     proc.langid = codeblock->langOid;
                                290                 : 
                                291                 :     /*
                                292                 :      * This is currently sufficient to get PLy_exec_function to work, but
 1970 tgl                       293 ECB             :      * someday we might need to be honest and use PLy_output_setup_func.
                                294                 :      */
 1970 tgl                       295 GIC          21 :     proc.result.typoid = VOIDOID;
                                296                 : 
                                297                 :     /*
                                298                 :      * Push execution context onto stack.  It is important that this get
                                299                 :      * popped again, so avoid putting anything that could throw error between
 1880 tgl                       300 ECB             :      * here and the PG_TRY.
                                301                 :      */
 1903 peter_e                   302 CBC          21 :     exec_ctx = PLy_push_execution_context(codeblock->atomic);
                                303                 : 
 4130 peter_e                   304 GIC          21 :     PG_TRY();
                                305                 :     {
                                306                 :         /*
                                307                 :          * Setup error traceback support for ereport().
                                308                 :          * plpython_inline_error_callback doesn't currently need exec_ctx, but
 1880 tgl                       309 ECB             :          * for consistency with plpython_call_handler we do it the same way.
                                310                 :          */
 1880 tgl                       311 CBC          21 :         plerrcontext.callback = plpython_inline_error_callback;
                                312              21 :         plerrcontext.arg = exec_ctx;
 1880 tgl                       313 GIC          21 :         plerrcontext.previous = error_context_stack;
 1880 tgl                       314 CBC          21 :         error_context_stack = &plerrcontext;
 1880 tgl                       315 ECB             : 
 4130 peter_e                   316 CBC          21 :         PLy_procedure_compile(&proc, codeblock->source_text);
 4044 tgl                       317 GIC          21 :         exec_ctx->curr_proc = &proc;
 1534 andres                    318 CBC          21 :         PLy_exec_function(fake_fcinfo, &proc);
                                319                 :     }
 4130 peter_e                   320              11 :     PG_CATCH();
 4130 peter_e                   321 ECB             :     {
 4044 tgl                       322 CBC          11 :         PLy_pop_execution_context();
 4130 peter_e                   323              11 :         PLy_procedure_delete(&proc);
 4130 peter_e                   324 GIC          11 :         PyErr_Clear();
 4130 peter_e                   325 CBC          11 :         PG_RE_THROW();
                                326                 :     }
 4130 peter_e                   327 GIC          10 :     PG_END_TRY();
 4130 peter_e                   328 ECB             : 
                                329                 :     /* Destroy the execution context */
 4044 tgl                       330 GIC          10 :     PLy_pop_execution_context();
 4130 peter_e                   331 ECB             : 
                                332                 :     /* Now clean up the transient procedure we made */
 4044 tgl                       333 CBC          10 :     PLy_procedure_delete(&proc);
                                334                 : 
 4130 peter_e                   335 GIC          10 :     PG_RETURN_VOID();
                                336                 : }
 4130 peter_e                   337 ECB             : 
                                338                 : static bool
 3955 bruce                     339 CBC         236 : PLy_procedure_is_trigger(Form_pg_proc procStruct)
                                340                 : {
 1130 tgl                       341 GIC         236 :     return (procStruct->prorettype == TRIGGEROID);
                                342                 : }
 4130 peter_e                   343 ECB             : 
                                344                 : static void
 4130 peter_e                   345 CBC         443 : plpython_error_callback(void *arg)
                                346                 : {
 1880 tgl                       347             443 :     PLyExecutionContext *exec_ctx = (PLyExecutionContext *) arg;
                                348                 : 
 4044                           349             443 :     if (exec_ctx->curr_proc)
 1956 peter_e                   350 ECB             :     {
 1956 peter_e                   351 GIC         440 :         if (exec_ctx->curr_proc->is_procedure)
                                352               4 :             errcontext("PL/Python procedure \"%s\"",
 1956 peter_e                   353 ECB             :                        PLy_procedure_name(exec_ctx->curr_proc));
                                354                 :         else
 1956 peter_e                   355 GIC         436 :             errcontext("PL/Python function \"%s\"",
 1956 peter_e                   356 ECB             :                        PLy_procedure_name(exec_ctx->curr_proc));
                                357                 :     }
 4130 peter_e                   358 GIC         443 : }
 4130 peter_e                   359 ECB             : 
                                360                 : static void
 4130 peter_e                   361 CBC          28 : plpython_inline_error_callback(void *arg)
 4130 peter_e                   362 ECB             : {
 4130 peter_e                   363 GIC          28 :     errcontext("PL/Python anonymous code block");
                                364              28 : }
 4044 tgl                       365 ECB             : 
                                366                 : PLyExecutionContext *
 4044 tgl                       367 CBC        1400 : PLy_current_execution_context(void)
 4044 tgl                       368 EUB             : {
 4044 tgl                       369 GIC        1400 :     if (PLy_execution_contexts == NULL)
 4044 tgl                       370 LBC           0 :         elog(ERROR, "no Python function is currently executing");
                                371                 : 
 4044 tgl                       372 GIC        1400 :     return PLy_execution_contexts;
                                373                 : }
 4044 tgl                       374 ECB             : 
                                375                 : MemoryContext
 2712 tgl                       376 GIC         779 : PLy_get_scratch_context(PLyExecutionContext *context)
                                377                 : {
                                378                 :     /*
                                379                 :      * A scratch context might never be needed in a given plpython procedure,
 2712 tgl                       380 ECB             :      * so allocate it on first request.
                                381                 :      */
 2712 tgl                       382 CBC         779 :     if (context->scratch_ctx == NULL)
 2712 tgl                       383 GIC         433 :         context->scratch_ctx =
                                384             433 :             AllocSetContextCreate(TopTransactionContext,
 2712 tgl                       385 ECB             :                                   "PL/Python scratch context",
                                386                 :                                   ALLOCSET_DEFAULT_SIZES);
 2712 tgl                       387 GIC         779 :     return context->scratch_ctx;
                                388                 : }
 2712 tgl                       389 ECB             : 
                                390                 : static PLyExecutionContext *
 1903 peter_e                   391 GIC         689 : PLy_push_execution_context(bool atomic_context)
                                392                 : {
                                393                 :     PLyExecutionContext *context;
                                394                 : 
 1903 peter_e                   395 ECB             :     /* Pick a memory context similar to what SPI uses. */
                                396                 :     context = (PLyExecutionContext *)
 1903 peter_e                   397 CBC         689 :         MemoryContextAlloc(atomic_context ? TopTransactionContext : PortalContext,
 1903 peter_e                   398 ECB             :                            sizeof(PLyExecutionContext));
 4044 tgl                       399 CBC         689 :     context->curr_proc = NULL;
 2712                           400             689 :     context->scratch_ctx = NULL;
 4044                           401             689 :     context->next = PLy_execution_contexts;
 4044 tgl                       402 GIC         689 :     PLy_execution_contexts = context;
                                403             689 :     return context;
                                404                 : }
 4044 tgl                       405 ECB             : 
                                406                 : static void
 4044 tgl                       407 CBC         689 : PLy_pop_execution_context(void)
                                408                 : {
 3955 bruce                     409             689 :     PLyExecutionContext *context = PLy_execution_contexts;
 4044 tgl                       410 EUB             : 
 4044 tgl                       411 GIC         689 :     if (context == NULL)
 4044 tgl                       412 LBC           0 :         elog(ERROR, "no Python function is currently executing");
                                413                 : 
 4044 tgl                       414 CBC         689 :     PLy_execution_contexts = context->next;
 4044 tgl                       415 ECB             : 
 2712 tgl                       416 CBC         689 :     if (context->scratch_ctx)
                                417             416 :         MemoryContextDelete(context->scratch_ctx);
 2712 tgl                       418 GIC         689 :     pfree(context);
 4044                           419             689 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a