LCOV - differential code coverage report
Current view: top level - src/pl/plpython - plpy_procedure.c (source / functions) Coverage Total Hit UNC UBC GIC GNC CBC DUB DCB
Current: d36b728949bf4e37ada1cd23e0f2aaa94f609a70 vs 52e118fe2f7e3381bdaa479816a7f72eda2ae517 Lines: 93.6 % 188 176 2 10 1 48 127 2 49
Current Date: 2026-06-29 16:15:13 +0200 Functions: 100.0 % 9 9 5 4 4
Baseline: lcov-20260630-baseline Branches: 68.3 % 142 97 8 37 24 73
Baseline Date: 2026-06-29 13:01:57 +0200 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 95.7 % 47 45 2 45
(30,360] days: 100.0 % 3 3 3
(360..) days: 92.8 % 138 128 10 1 127
Function coverage date bins:
(7,30] days: 100.0 % 5 5 5
(360..) days: 100.0 % 4 4 4
Branch coverage date bins:
(7,30] days: 73.3 % 30 22 8 22
(30,360] days: 100.0 % 2 2 2
(360..) days: 66.4 % 110 73 37 73

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*
                                  2                 :                :  * Python procedure manipulation for plpython
                                  3                 :                :  *
                                  4                 :                :  * src/pl/plpython/plpy_procedure.c
                                  5                 :                :  */
                                  6                 :                : 
                                  7                 :                : #include "postgres.h"
                                  8                 :                : 
                                  9                 :                : #include "catalog/pg_proc.h"
                                 10                 :                : #include "catalog/pg_type.h"
                                 11                 :                : #include "commands/event_trigger.h"
                                 12                 :                : #include "commands/trigger.h"
                                 13                 :                : #include "funcapi.h"
                                 14                 :                : #include "plpy_elog.h"
                                 15                 :                : #include "plpy_exec.h"
                                 16                 :                : #include "plpy_main.h"
                                 17                 :                : #include "plpy_procedure.h"
                                 18                 :                : #include "plpy_util.h"
                                 19                 :                : #include "utils/builtins.h"
                                 20                 :                : #include "utils/funccache.h"
                                 21                 :                : #include "utils/syscache.h"
                                 22                 :                : 
                                 23                 :                : static void PLy_procedure_create(PLyProcedure *proc,
                                 24                 :                :                                  HeapTuple procTup,
                                 25                 :                :                                  Oid fn_oid,
                                 26                 :                :                                  PLyTrigType is_trigger);
                                 27                 :                : static char *PLy_procedure_munge_source(const char *name, const char *src);
                                 28                 :                : static void PLy_compile_callback(FunctionCallInfo fcinfo,
                                 29                 :                :                                  HeapTuple procTup,
                                 30                 :                :                                  const CachedFunctionHashKey *hashkey,
                                 31                 :                :                                  CachedFunction *cfunc,
                                 32                 :                :                                  bool forValidator);
                                 33                 :                : static void PLy_delete_callback(CachedFunction *cfunc);
                                 34                 :                : static void RemovePLyProcedureCache(void *arg);
                                 35                 :                : 
                                 36                 :                : 
                                 37                 :                : /*
                                 38                 :                :  * PLy_procedure_name: get the name of the specified procedure.
                                 39                 :                :  *
                                 40                 :                :  * NB: this returns the SQL name, not the internal Python procedure name
                                 41                 :                :  */
                                 42                 :                : char *
 5308 peter_e@gmx.net            43                 :CBC         551 : PLy_procedure_name(PLyProcedure *proc)
                                 44                 :                : {
                                 45         [ -  + ]:            551 :     if (proc == NULL)
 5308 peter_e@gmx.net            46                 :UBC           0 :         return "<unknown procedure>";
 5308 peter_e@gmx.net            47                 :CBC         551 :     return proc->proname;
                                 48                 :                : }
                                 49                 :                : 
                                 50                 :                : /*
                                 51                 :                :  * PLy_procedure_get: returns a PLyProcedureCache struct for the function,
                                 52                 :                :  * making it valid if necessary.
                                 53                 :                :  *
                                 54                 :                :  * The PLyProcedureCache contains a pointer to the long-lived PLyProcedure
                                 55                 :                :  * (managed by funccache.c) and execution-specific state like SRF state.
                                 56                 :                :  *
                                 57                 :                :  * For SRFs, if we are resuming execution (srfstate->iter != NULL), we skip
                                 58                 :                :  * revalidation and continue using the same PLyProcedure to ensure consistent
                                 59                 :                :  * behavior throughout the SRF execution.
                                 60                 :                :  */
                                 61                 :                : PLyProcedureCache *
    9 tgl@sss.pgh.pa.us          62                 :GNC         994 : PLy_procedure_get(FunctionCallInfo fcinfo, bool forValidator)
                                 63                 :                : {
                                 64                 :            994 :     FmgrInfo   *finfo = fcinfo->flinfo;
                                 65                 :                :     PLyProcedureCache *pcache;
                                 66                 :                :     PLyProcedure *proc;
                                 67                 :                : 
                                 68                 :                :     /*
                                 69                 :                :      * If this is the first execution for this FmgrInfo, set up a cache struct
                                 70                 :                :      * (initially containing null pointers).  The cache must live as long as
                                 71                 :                :      * the FmgrInfo, so it goes in fn_mcxt.  Also set up a memory context
                                 72                 :                :      * callback that will be invoked when fn_mcxt is reset/deleted.
                                 73                 :                :      */
                                 74                 :            994 :     pcache = finfo->fn_extra;
                                 75         [ +  + ]:            994 :     if (pcache == NULL)
                                 76                 :                :     {
                                 77                 :                :         pcache = (PLyProcedureCache *)
                                 78                 :            799 :             MemoryContextAllocZero(finfo->fn_mcxt, sizeof(PLyProcedureCache));
                                 79                 :                : 
                                 80                 :            799 :         pcache->fcontext = finfo->fn_mcxt;
                                 81                 :            799 :         pcache->mcb.func = RemovePLyProcedureCache;
                                 82                 :            799 :         pcache->mcb.arg = pcache;
                                 83                 :                : 
                                 84                 :            799 :         MemoryContextRegisterResetCallback(finfo->fn_mcxt, &pcache->mcb);
                                 85                 :                : 
                                 86                 :            799 :         finfo->fn_extra = pcache;
                                 87                 :                :     }
                                 88                 :                : 
                                 89                 :                :     /*
                                 90                 :                :      * If we are resuming execution of a set-returning function, just keep
                                 91                 :                :      * using the same cache.  We do not ask funccache.c to re-validate the
                                 92                 :                :      * PLyProcedure: we want to run to completion using the function's initial
                                 93                 :                :      * definition.
                                 94                 :                :      *
                                 95                 :                :      * A live iterator (srfstate->iter != NULL) reliably means a genuine
                                 96                 :                :      * resume: when an iteration ends for any reason, srfstate->iter is reset
                                 97                 :                :      * to NULL (see comments for PLy_function_cleanup_srfstate).
                                 98                 :                :      */
                                 99   [ +  +  +  - ]:            994 :     if (pcache->srfstate != NULL && pcache->srfstate->iter != NULL)
                                100                 :                :     {
                                101         [ -  + ]:            156 :         Assert(pcache->proc != NULL);
                                102                 :            156 :         return pcache;
                                103                 :                :     }
                                104                 :                : 
                                105                 :                :     /*
                                106                 :                :      * Look up, or re-validate, the long-lived hash entry.  Like SQL-language
                                107                 :                :      * functions, make the hash key depend on the result of
                                108                 :                :      * get_call_result_type() when that's composite, so that we can safely
                                109                 :                :      * assume that we'll build a new hash entry if the composite rowtype
                                110                 :                :      * changes.
                                111                 :                :      */
                                112                 :                :     proc = (PLyProcedure *)
                                113                 :            838 :         cached_function_compile(fcinfo,
                                114                 :            838 :                                 (CachedFunction *) pcache->proc,
                                115                 :                :                                 PLy_compile_callback,
                                116                 :                :                                 PLy_delete_callback,
                                117                 :                :                                 sizeof(PLyProcedure),
                                118                 :                :                                 true,
                                119                 :                :                                 forValidator);
                                120                 :                : 
                                121                 :                :     /*
                                122                 :                :      * Install the hash pointer in the PLyProcedureCache, and increment its
                                123                 :                :      * use count to reflect that.  If cached_function_compile gave us back a
                                124                 :                :      * different hash entry than we were using before, we must decrement that
                                125                 :                :      * one's use count.
                                126                 :                :      */
                                127         [ +  + ]:            834 :     if (proc != pcache->proc)
                                128                 :                :     {
                                129         [ -  + ]:            795 :         if (pcache->proc != NULL)
                                130                 :                :         {
    9 tgl@sss.pgh.pa.us         131         [ #  # ]:UNC           0 :             Assert(pcache->proc->cfunc.use_count > 0);
                                132                 :              0 :             pcache->proc->cfunc.use_count--;
                                133                 :                :         }
    9 tgl@sss.pgh.pa.us         134                 :GNC         795 :         pcache->proc = proc;
                                135                 :            795 :         proc->cfunc.use_count++;
                                136                 :                :     }
                                137                 :                : 
                                138                 :            834 :     return pcache;
                                139                 :                : }
                                140                 :                : 
                                141                 :                : /*
                                142                 :                :  * Create (well, fill in) a new PLyProcedure structure
                                143                 :                :  */
                                144                 :                : static void
                                145                 :            350 : PLy_procedure_create(PLyProcedure *proc,
                                146                 :                :                      HeapTuple procTup,
                                147                 :                :                      Oid fn_oid,
                                148                 :                :                      PLyTrigType is_trigger)
                                149                 :                : {
                                150                 :                :     char        procName[NAMEDATALEN + 256];
                                151                 :                :     Form_pg_proc procStruct;
                                152                 :                :     MemoryContext cxt;
                                153                 :                :     MemoryContext oldcxt;
                                154                 :                :     int         rv;
                                155                 :                :     char       *ptr;
                                156                 :                : 
 5308 peter_e@gmx.net           157                 :CBC         350 :     procStruct = (Form_pg_proc) GETSTRUCT(procTup);
                                158                 :            700 :     rv = snprintf(procName, sizeof(procName),
                                159                 :                :                   "__plpython_procedure_%s_%u",
                                160                 :            350 :                   NameStr(procStruct->proname),
                                161                 :                :                   fn_oid);
                                162   [ +  -  -  + ]:            350 :     if (rv >= sizeof(procName) || rv < 0)
 5308 peter_e@gmx.net           163         [ #  # ]:UBC           0 :         elog(ERROR, "procedure name would overrun buffer");
                                164                 :                : 
                                165                 :                :     /* Replace any not-legal-in-Python-names characters with '_' */
 3787 tgl@sss.pgh.pa.us         166         [ +  + ]:CBC       16344 :     for (ptr = procName; *ptr; ptr++)
                                167                 :                :     {
                                168   [ +  +  +  + ]:          15994 :         if (!((*ptr >= 'A' && *ptr <= 'Z') ||
                                169   [ +  +  -  + ]:          15992 :               (*ptr >= 'a' && *ptr <= 'z') ||
                                170   [ +  +  +  + ]:           4302 :               (*ptr >= '0' && *ptr <= '9')))
                                171                 :           2434 :             *ptr = '_';
                                172                 :                :     }
                                173                 :                : 
                                174                 :                :     /* Create long-lived context that all procedure info will live in */
 3017                           175                 :            350 :     cxt = AllocSetContextCreate(TopMemoryContext,
                                176                 :                :                                 "PL/Python function",
                                177                 :                :                                 ALLOCSET_DEFAULT_SIZES);
                                178                 :                : 
 3890                           179                 :            350 :     oldcxt = MemoryContextSwitchTo(cxt);
                                180                 :                : 
                                181                 :            350 :     proc->mcxt = cxt;
                                182                 :                : 
 5308 peter_e@gmx.net           183         [ +  + ]:            350 :     PG_TRY();
                                184                 :                :     {
                                185                 :                :         Datum       protrftypes_datum;
                                186                 :                :         Datum       prosrcdatum;
                                187                 :                :         bool        isnull;
                                188                 :                :         char       *procSource;
                                189                 :                :         int         i;
                                190                 :                : 
 3890 tgl@sss.pgh.pa.us         191                 :            350 :         proc->proname = pstrdup(NameStr(procStruct->proname));
 3017                           192                 :            350 :         MemoryContextSetIdentifier(cxt, proc->proname);
 3890                           193                 :            350 :         proc->pyname = pstrdup(procName);
 3738                           194                 :            350 :         proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
                                195                 :            350 :         proc->is_setof = procStruct->proretset;
 3042 peter_e@gmx.net           196                 :            350 :         proc->is_procedure = (procStruct->prokind == PROKIND_PROCEDURE);
  784 tgl@sss.pgh.pa.us         197                 :            350 :         proc->is_trigger = is_trigger;
 3738                           198                 :            350 :         proc->src = NULL;
                                199                 :            350 :         proc->argnames = NULL;
 3148                           200                 :            350 :         proc->args = NULL;
 3890                           201                 :            350 :         proc->nargs = 0;
                                202                 :            350 :         proc->langid = procStruct->prolang;
                                203                 :            350 :         protrftypes_datum = SysCacheGetAttr(PROCOID, procTup,
                                204                 :                :                                             Anum_pg_proc_protrftypes,
                                205                 :                :                                             &isnull);
                                206         [ +  + ]:            350 :         proc->trftypes = isnull ? NIL : oid_array_to_list(protrftypes_datum);
 3738                           207                 :            350 :         proc->code = NULL;
                                208                 :            350 :         proc->statics = NULL;
 3890                           209                 :            350 :         proc->globals = NULL;
 3738                           210                 :            350 :         proc->calldepth = 0;
                                211                 :            350 :         proc->argstack = NULL;
                                212                 :                : 
                                213                 :                :         /*
                                214                 :                :          * get information required for output conversion of the return value,
                                215                 :                :          * but only if this isn't a trigger.
                                216                 :                :          */
  313 peter@eisentraut.org      217         [ +  + ]:GNC         350 :         if (is_trigger == PLPY_NOT_TRIGGER)
                                218                 :                :         {
 3148 tgl@sss.pgh.pa.us         219                 :CBC         296 :             Oid         rettype = procStruct->prorettype;
                                220                 :                :             HeapTuple   rvTypeTup;
                                221                 :                :             Form_pg_type rvTypeStruct;
                                222                 :                : 
                                223                 :            296 :             rvTypeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettype));
 5308 peter_e@gmx.net           224         [ -  + ]:            296 :             if (!HeapTupleIsValid(rvTypeTup))
 3148 tgl@sss.pgh.pa.us         225         [ #  # ]:UBC           0 :                 elog(ERROR, "cache lookup failed for type %u", rettype);
 5308 peter_e@gmx.net           226                 :CBC         296 :             rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
                                227                 :                : 
                                228                 :                :             /* Disallow pseudotype result, except for void or record */
                                229         [ +  + ]:            296 :             if (rvTypeStruct->typtype == TYPTYPE_PSEUDO)
                                230                 :                :             {
 3148 tgl@sss.pgh.pa.us         231   [ +  +  +  + ]:             72 :                 if (rettype == VOIDOID ||
                                232                 :                :                     rettype == RECORDOID)
                                233                 :                :                      /* okay */ ;
 2070                           234   [ -  +  -  - ]:              1 :                 else if (rettype == TRIGGEROID || rettype == EVENT_TRIGGEROID)
 5308 peter_e@gmx.net           235         [ +  - ]:              1 :                     ereport(ERROR,
                                236                 :                :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                237                 :                :                              errmsg("trigger functions can only be called as triggers")));
                                238                 :                :                 else
 5308 peter_e@gmx.net           239         [ #  # ]:UBC           0 :                     ereport(ERROR,
                                240                 :                :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                241                 :                :                              errmsg("PL/Python functions cannot return type %s",
                                242                 :                :                                     format_type_be(rettype))));
                                243                 :                :             }
                                244                 :                : 
                                245                 :                :             /* set up output function for procedure result */
 3148 tgl@sss.pgh.pa.us         246                 :CBC         295 :             PLy_output_setup_func(&proc->result, proc->mcxt,
                                247                 :                :                                   rettype, -1, proc);
                                248                 :                : 
 5308 peter_e@gmx.net           249                 :            295 :             ReleaseSysCache(rvTypeTup);
                                250                 :                :         }
                                251                 :                :         else
                                252                 :                :         {
                                253                 :                :             /*
                                254                 :                :              * In a trigger function, we use proc->result and proc->result_in
                                255                 :                :              * for converting tuples, but we don't yet have enough info to set
                                256                 :                :              * them up.  PLy_exec_trigger will deal with it.
                                257                 :                :              */
 3148 tgl@sss.pgh.pa.us         258                 :             54 :             proc->result.typoid = InvalidOid;
                                259                 :             54 :             proc->result_in.typoid = InvalidOid;
                                260                 :                :         }
                                261                 :                : 
                                262                 :                :         /*
                                263                 :                :          * Now get information required for input conversion of the
                                264                 :                :          * procedure's arguments.  Note that we ignore output arguments here.
                                265                 :                :          * If the function returns record, those I/O functions will be set up
                                266                 :                :          * when the function is first called.
                                267                 :                :          */
 5308 peter_e@gmx.net           268         [ +  + ]:            349 :         if (procStruct->pronargs)
                                269                 :                :         {
                                270                 :                :             Oid        *types;
                                271                 :                :             char      **names,
                                272                 :                :                        *modes;
                                273                 :                :             int         pos,
                                274                 :                :                         total;
                                275                 :                : 
                                276                 :                :             /* extract argument type info from the pg_proc tuple */
                                277                 :            161 :             total = get_func_arg_info(procTup, &types, &names, &modes);
                                278                 :                : 
                                279                 :                :             /* count number of in+inout args into proc->nargs */
                                280         [ +  + ]:            161 :             if (modes == NULL)
                                281                 :            144 :                 proc->nargs = total;
                                282                 :                :             else
                                283                 :                :             {
                                284                 :                :                 /* proc->nargs was initialized to 0 above */
                                285         [ +  + ]:             64 :                 for (i = 0; i < total; i++)
                                286                 :                :                 {
 1846 tgl@sss.pgh.pa.us         287         [ +  + ]:             47 :                     if (modes[i] != PROARGMODE_OUT &&
 5308 peter_e@gmx.net           288         [ +  - ]:             29 :                         modes[i] != PROARGMODE_TABLE)
                                289                 :             29 :                         (proc->nargs)++;
                                290                 :                :                 }
                                291                 :                :             }
                                292                 :                : 
                                293                 :                :             /* Allocate arrays for per-input-argument data */
  203 michael@paquier.xyz       294                 :GNC         161 :             proc->argnames = (char **) palloc0_array(char *, proc->nargs);
                                295                 :            161 :             proc->args = (PLyDatumToOb *) palloc0_array(PLyDatumToOb, proc->nargs);
                                296                 :                : 
 5308 peter_e@gmx.net           297         [ +  + ]:CBC         425 :             for (i = pos = 0; i < total; i++)
                                298                 :                :             {
                                299                 :                :                 HeapTuple   argTypeTup;
                                300                 :                :                 Form_pg_type argTypeStruct;
                                301                 :                : 
                                302         [ +  + ]:            264 :                 if (modes &&
 1846 tgl@sss.pgh.pa.us         303         [ +  + ]:             47 :                     (modes[i] == PROARGMODE_OUT ||
 5308 peter_e@gmx.net           304         [ -  + ]:             29 :                      modes[i] == PROARGMODE_TABLE))
                                305                 :             18 :                     continue;   /* skip OUT arguments */
                                306                 :                : 
                                307         [ -  + ]:            246 :                 Assert(types[i] == procStruct->proargtypes.values[pos]);
                                308                 :                : 
                                309                 :            246 :                 argTypeTup = SearchSysCache1(TYPEOID,
                                310                 :            246 :                                              ObjectIdGetDatum(types[i]));
                                311         [ -  + ]:            246 :                 if (!HeapTupleIsValid(argTypeTup))
 5308 peter_e@gmx.net           312         [ #  # ]:UBC           0 :                     elog(ERROR, "cache lookup failed for type %u", types[i]);
 5308 peter_e@gmx.net           313                 :CBC         246 :                 argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
                                314                 :                : 
                                315                 :                :                 /* disallow pseudotype arguments */
 3148 tgl@sss.pgh.pa.us         316         [ -  + ]:            246 :                 if (argTypeStruct->typtype == TYPTYPE_PSEUDO)
 3148 tgl@sss.pgh.pa.us         317         [ #  # ]:UBC           0 :                     ereport(ERROR,
                                318                 :                :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                319                 :                :                              errmsg("PL/Python functions cannot accept type %s",
                                320                 :                :                                     format_type_be(types[i]))));
                                321                 :                : 
                                322                 :                :                 /* set up I/O function info */
 3148 tgl@sss.pgh.pa.us         323                 :CBC         246 :                 PLy_input_setup_func(&proc->args[pos], proc->mcxt,
                                324                 :            246 :                                      types[i], -1,  /* typmod not known */
                                325                 :                :                                      proc);
                                326                 :                : 
                                327                 :                :                 /* get argument name */
 3890                           328         [ +  + ]:            246 :                 proc->argnames[pos] = names ? pstrdup(names[i]) : NULL;
                                329                 :                : 
 5308 peter_e@gmx.net           330                 :            246 :                 ReleaseSysCache(argTypeTup);
                                331                 :                : 
                                332                 :            246 :                 pos++;
                                333                 :                :             }
                                334                 :                :         }
                                335                 :                : 
                                336                 :                :         /*
                                337                 :                :          * get the text of the function.
                                338                 :                :          */
 1193 dgustafsson@postgres      339                 :            349 :         prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procTup,
                                340                 :                :                                              Anum_pg_proc_prosrc);
 5308 peter_e@gmx.net           341                 :            349 :         procSource = TextDatumGetCString(prosrcdatum);
                                342                 :                : 
                                343                 :            349 :         PLy_procedure_compile(proc, procSource);
                                344                 :                : 
                                345                 :            346 :         pfree(procSource);
                                346                 :                :     }
                                347                 :              4 :     PG_CATCH();
                                348                 :                :     {
 3890 tgl@sss.pgh.pa.us         349                 :              4 :         MemoryContextSwitchTo(oldcxt);
 5308 peter_e@gmx.net           350                 :              4 :         PLy_procedure_delete(proc);
                                351                 :              4 :         PG_RE_THROW();
                                352                 :                :     }
                                353         [ -  + ]:            346 :     PG_END_TRY();
                                354                 :                : 
 3890 tgl@sss.pgh.pa.us         355                 :            346 :     MemoryContextSwitchTo(oldcxt);
 5308 peter_e@gmx.net           356                 :GIC         346 : }
                                357                 :                : 
                                358                 :                : /*
                                359                 :                :  * Insert the procedure into the Python interpreter
                                360                 :                :  */
                                361                 :                : void
 5308 peter_e@gmx.net           362                 :CBC         370 : PLy_procedure_compile(PLyProcedure *proc, const char *src)
                                363                 :                : {
                                364                 :            370 :     PyObject   *crv = NULL;
                                365                 :                :     char       *msrc;
                                366                 :                :     PyObject   *code0;
                                367                 :                : 
                                368                 :            370 :     proc->globals = PyDict_Copy(PLy_interp_globals);
                                369                 :                : 
                                370                 :                :     /*
                                371                 :                :      * SD is private preserved data between calls. GD is global data shared by
                                372                 :                :      * all functions
                                373                 :                :      */
                                374                 :            370 :     proc->statics = PyDict_New();
 3164                           375         [ -  + ]:            370 :     if (!proc->statics)
 3164 peter_e@gmx.net           376                 :UBC           0 :         PLy_elog(ERROR, NULL);
 5308 peter_e@gmx.net           377                 :CBC         370 :     PyDict_SetItemString(proc->globals, "SD", proc->statics);
                                378                 :                : 
                                379                 :                :     /*
                                380                 :                :      * insert the function code into the interpreter
                                381                 :                :      */
                                382                 :            370 :     msrc = PLy_procedure_munge_source(proc->pyname, src);
                                383                 :                :     /* Save the mangled source for later inclusion in tracebacks */
 3890 tgl@sss.pgh.pa.us         384                 :            370 :     proc->src = MemoryContextStrdup(proc->mcxt, msrc);
  475 peter@eisentraut.org      385                 :            370 :     code0 = Py_CompileString(msrc, "<string>", Py_file_input);
                                386         [ +  + ]:            370 :     if (code0)
                                387                 :            367 :         crv = PyEval_EvalCode(code0, proc->globals, NULL);
 5308 peter_e@gmx.net           388                 :            370 :     pfree(msrc);
                                389                 :                : 
                                390         [ +  + ]:            370 :     if (crv != NULL)
                                391                 :                :     {
                                392                 :                :         int         clen;
                                393                 :                :         char        call[NAMEDATALEN + 256];
                                394                 :                : 
                                395                 :                :         Py_DECREF(crv);
                                396                 :                : 
                                397                 :                :         /*
                                398                 :                :          * compile a call to the function
                                399                 :                :          */
                                400                 :            367 :         clen = snprintf(call, sizeof(call), "%s()", proc->pyname);
                                401   [ +  -  -  + ]:            367 :         if (clen < 0 || clen >= sizeof(call))
 5308 peter_e@gmx.net           402         [ #  # ]:UBC           0 :             elog(ERROR, "string would overflow buffer");
 5308 peter_e@gmx.net           403                 :CBC         367 :         proc->code = Py_CompileString(call, "<string>", Py_eval_input);
                                404         [ +  - ]:            367 :         if (proc->code != NULL)
                                405                 :            367 :             return;
                                406                 :                :     }
                                407                 :                : 
                                408         [ +  - ]:              3 :     if (proc->proname)
                                409                 :              3 :         PLy_elog(ERROR, "could not compile PL/Python function \"%s\"",
                                410                 :                :                  proc->proname);
                                411                 :                :     else
 5308 peter_e@gmx.net           412                 :UBC           0 :         PLy_elog(ERROR, "could not compile anonymous PL/Python code block");
                                413                 :                : }
                                414                 :                : 
                                415                 :                : void
 5308 peter_e@gmx.net           416                 :CBC          30 : PLy_procedure_delete(PLyProcedure *proc)
                                417                 :                : {
                                418                 :             30 :     Py_XDECREF(proc->code);
                                419                 :             30 :     Py_XDECREF(proc->statics);
                                420                 :             30 :     Py_XDECREF(proc->globals);
 3890 tgl@sss.pgh.pa.us         421                 :             30 :     MemoryContextDelete(proc->mcxt);
 5308 peter_e@gmx.net           422                 :             30 : }
                                423                 :                : 
                                424                 :                : static char *
                                425                 :            370 : PLy_procedure_munge_source(const char *name, const char *src)
                                426                 :                : {
                                427                 :                :     char       *mrc,
                                428                 :                :                *mp;
                                429                 :                :     const char *sp;
                                430                 :                :     size_t      mlen;
                                431                 :                :     int         plen;
                                432                 :                : 
                                433                 :                :     /*
                                434                 :                :      * room for function source and the def statement
                                435                 :                :      */
                                436                 :            370 :     mlen = (strlen(src) * 2) + strlen(name) + 16;
                                437                 :                : 
                                438                 :            370 :     mrc = palloc(mlen);
                                439                 :            370 :     plen = snprintf(mrc, mlen, "def %s():\n\t", name);
                                440   [ +  -  -  + ]:            370 :     Assert(plen >= 0 && plen < mlen);
                                441                 :                : 
                                442                 :            370 :     sp = src;
                                443                 :            370 :     mp = mrc + plen;
                                444                 :                : 
                                445         [ +  + ]:          43002 :     while (*sp != '\0')
                                446                 :                :     {
                                447   [ +  +  +  + ]:          42632 :         if (*sp == '\r' && *(sp + 1) == '\n')
                                448                 :              3 :             sp++;
                                449                 :                : 
                                450   [ +  +  +  + ]:          42632 :         if (*sp == '\n' || *sp == '\r')
                                451                 :                :         {
                                452                 :           1810 :             *mp++ = '\n';
                                453                 :           1810 :             *mp++ = '\t';
                                454                 :           1810 :             sp++;
                                455                 :                :         }
                                456                 :                :         else
                                457                 :          40822 :             *mp++ = *sp++;
                                458                 :                :     }
                                459                 :            370 :     *mp++ = '\n';
                                460                 :            370 :     *mp++ = '\n';
                                461                 :            370 :     *mp = '\0';
                                462                 :                : 
                                463         [ -  + ]:            370 :     if (mp > (mrc + mlen))
 2521 michael@paquier.xyz       464         [ #  # ]:UBC           0 :         elog(FATAL, "buffer overrun in PLy_procedure_munge_source");
                                465                 :                : 
 5308 peter_e@gmx.net           466                 :CBC         370 :     return mrc;
                                467                 :                : }
                                468                 :                : 
                                469                 :                : /*
                                470                 :                :  * Compile callback for funccache.c.
                                471                 :                :  *
                                472                 :                :  * cached_function_compile() calls this when it needs to (re)compile the
                                473                 :                :  * long-lived PLyProcedure for a function.  The CachedFunction handed to us is
                                474                 :                :  * pre-zeroed workspace of size sizeof(PLyProcedure); we just have to fill in
                                475                 :                :  * the PL/Python-specific fields.
                                476                 :                :  */
                                477                 :                : static void
    9 tgl@sss.pgh.pa.us         478                 :GNC         350 : PLy_compile_callback(FunctionCallInfo fcinfo,
                                479                 :                :                      HeapTuple procTup,
                                480                 :                :                      const CachedFunctionHashKey *hashkey,
                                481                 :                :                      CachedFunction *cfunc,
                                482                 :                :                      bool forValidator)
                                483                 :                : {
                                484                 :            350 :     PLyProcedure *proc = (PLyProcedure *) cfunc;
                                485                 :            350 :     Oid         fn_oid = fcinfo->flinfo->fn_oid;
                                486                 :                :     PLyTrigType is_trigger;
                                487                 :                : 
                                488                 :                :     /*
                                489                 :                :      * Derive the trigger type from the call context, matching what
                                490                 :                :      * plpython3_call_handler dispatches on.
                                491                 :                :      */
                                492   [ +  +  +  + ]:            350 :     if (CALLED_AS_TRIGGER(fcinfo))
                                493                 :             53 :         is_trigger = PLPY_TRIGGER;
                                494   [ +  +  +  + ]:            297 :     else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
                                495                 :              1 :         is_trigger = PLPY_EVENT_TRIGGER;
                                496                 :                :     else
                                497                 :            296 :         is_trigger = PLPY_NOT_TRIGGER;
                                498                 :                : 
                                499                 :            350 :     PLy_procedure_create(proc, procTup, fn_oid, is_trigger);
                                500                 :            346 : }
                                501                 :                : 
                                502                 :                : /*
                                503                 :                :  * Deletion callback for funccache.c.
                                504                 :                :  *
                                505                 :                :  * cached_function_compile() calls this when it discards a cache entry, which
                                506                 :                :  * only happens once the entry's use count has dropped to zero.  We must free
                                507                 :                :  * the subsidiary data but not the CachedFunction struct itself.
                                508                 :                :  */
                                509                 :                : static void
                                510                 :              5 : PLy_delete_callback(CachedFunction *cfunc)
                                511                 :                : {
                                512                 :              5 :     PLyProcedure *proc = (PLyProcedure *) cfunc;
                                513                 :                : 
                                514         [ -  + ]:              5 :     Assert(proc->cfunc.use_count == 0);
                                515         [ -  + ]:              5 :     Assert(proc->calldepth == 0);
                                516                 :                : 
                                517                 :              5 :     PLy_procedure_delete(proc);
                                518                 :              5 : }
                                519                 :                : 
                                520                 :                : /*
                                521                 :                :  * MemoryContext callback function
                                522                 :                :  *
                                523                 :                :  * We register this in the memory context that contains a PLyProcedureCache
                                524                 :                :  * struct (that is, the FmgrInfo's fn_mcxt).  When the memory context is reset
                                525                 :                :  * or deleted, we release the reference count (if any) that the cache holds on
                                526                 :                :  * the long-lived hash entry.  Note that this will happen even during error
                                527                 :                :  * aborts.
                                528                 :                :  *
                                529                 :                :  * This is also our opportunity to release the Python references held by an
                                530                 :                :  * interrupted set-returning function.  ShutdownPLyFunction() handles that for
                                531                 :                :  * routine in-query cancellation cases, but it does not run during an error
                                532                 :                :  * abort; this callback does, so it is the backstop that prevents leaking the
                                533                 :                :  * SRF's iterator and saved arguments when a query errors out mid-iteration.
                                534                 :                :  */
                                535                 :                : static void
                                536                 :            799 : RemovePLyProcedureCache(void *arg)
                                537                 :                : {
                                538                 :            799 :     PLyProcedureCache *pcache = (PLyProcedureCache *) arg;
                                539                 :                : 
                                540                 :                :     /* Release any Python state left behind by an interrupted SRF */
                                541                 :            799 :     PLy_function_cleanup_srfstate(pcache);
                                542                 :                : 
                                543                 :                :     /* Release reference count on PLyProcedure */
                                544         [ +  + ]:            799 :     if (pcache->proc != NULL)
                                545                 :                :     {
                                546         [ -  + ]:            530 :         Assert(pcache->proc->cfunc.use_count > 0);
                                547                 :            530 :         pcache->proc->cfunc.use_count--;
                                548                 :            530 :         pcache->proc = NULL;
                                549                 :                :     }
                                550                 :                : 
                                551                 :                :     /* We needn't free the pcache object itself, context cleanup does that */
                                552                 :            799 : }
        

Generated by: LCOV version 2.0-1