LCOV - differential code coverage report
Current view: top level - src/pl/plpython - plpy_procedure.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: a2387c32f2f8a1643c7d71b951587e6bcb2d4744 vs 371a302eecdc82274b0ae2967d18fd726a0aa6a1 Lines: 93.8 % 192 180 12 8 172 4
Current Date: 2025-10-26 12:31:50 -0700 Functions: 100.0 % 8 8 2 6 2
Baseline: lcov-20251027-010456-baseline Branches: 68.3 % 142 97 45 6 91
Baseline Date: 2025-10-26 11:01:32 +1300 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(1,7] days: 100.0 % 2 2 2
(30,360] days: 100.0 % 9 9 6 3
(360..) days: 93.4 % 181 169 12 169
Function coverage date bins:
(30,360] days: 100.0 % 2 2 2
(360..) days: 100.0 % 6 6 6
Branch coverage date bins:
(30,360] days: 100.0 % 8 8 6 2
(360..) days: 66.4 % 134 89 45 89

 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 "access/htup_details.h"
                                 10                 :                : #include "catalog/pg_proc.h"
                                 11                 :                : #include "catalog/pg_type.h"
                                 12                 :                : #include "funcapi.h"
                                 13                 :                : #include "plpy_elog.h"
                                 14                 :                : #include "plpy_main.h"
                                 15                 :                : #include "plpy_procedure.h"
                                 16                 :                : #include "plpy_util.h"
                                 17                 :                : #include "utils/builtins.h"
                                 18                 :                : #include "utils/hsearch.h"
                                 19                 :                : #include "utils/memutils.h"
                                 20                 :                : #include "utils/syscache.h"
                                 21                 :                : 
                                 22                 :                : static HTAB *PLy_procedure_cache = NULL;
                                 23                 :                : 
                                 24                 :                : static PLyProcedure *PLy_procedure_create(HeapTuple procTup, Oid fn_oid, PLyTrigType is_trigger);
                                 25                 :                : static bool PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup);
                                 26                 :                : static char *PLy_procedure_munge_source(const char *name, const char *src);
                                 27                 :                : 
                                 28                 :                : 
                                 29                 :                : void
 5062 peter_e@gmx.net            30                 :CBC          23 : init_procedure_caches(void)
                                 31                 :                : {
                                 32                 :                :     HASHCTL     hash_ctl;
                                 33                 :                : 
 4658 tgl@sss.pgh.pa.us          34                 :             23 :     hash_ctl.keysize = sizeof(PLyProcedureKey);
 5062 peter_e@gmx.net            35                 :             23 :     hash_ctl.entrysize = sizeof(PLyProcedureEntry);
                                 36                 :             23 :     PLy_procedure_cache = hash_create("PL/Python procedures", 32, &hash_ctl,
                                 37                 :                :                                       HASH_ELEM | HASH_BLOBS);
                                 38                 :             23 : }
                                 39                 :                : 
                                 40                 :                : /*
                                 41                 :                :  * PLy_procedure_name: get the name of the specified procedure.
                                 42                 :                :  *
                                 43                 :                :  * NB: this returns the SQL name, not the internal Python procedure name
                                 44                 :                :  */
                                 45                 :                : char *
                                 46                 :            531 : PLy_procedure_name(PLyProcedure *proc)
                                 47                 :                : {
                                 48         [ -  + ]:            531 :     if (proc == NULL)
 5062 peter_e@gmx.net            49                 :UBC           0 :         return "<unknown procedure>";
 5062 peter_e@gmx.net            50                 :CBC         531 :     return proc->proname;
                                 51                 :                : }
                                 52                 :                : 
                                 53                 :                : /*
                                 54                 :                :  * PLy_procedure_get: returns a cached PLyProcedure, or creates, stores and
                                 55                 :                :  * returns a new PLyProcedure.
                                 56                 :                :  *
                                 57                 :                :  * fn_oid is the OID of the function requested
                                 58                 :                :  * fn_rel is InvalidOid or the relation this function triggers on
                                 59                 :                :  * is_trigger denotes whether the function is a trigger function
                                 60                 :                :  *
                                 61                 :                :  * The reason that both fn_rel and is_trigger need to be passed is that when
                                 62                 :                :  * trigger functions get validated we don't know which relation(s) they'll
                                 63                 :                :  * be used with, so no sensible fn_rel can be passed.  Also, in that case
                                 64                 :                :  * we can't make a cache entry because we can't construct the right cache key.
                                 65                 :                :  * To forestall leakage of the PLyProcedure in such cases, delete it after
                                 66                 :                :  * construction and return NULL.  That's okay because the only caller that
                                 67                 :                :  * would pass that set of values is plpython3_validator, which ignores our
                                 68                 :                :  * result anyway.
                                 69                 :                :  */
                                 70                 :                : PLyProcedure *
   67 peter@eisentraut.org       71                 :GNC         951 : PLy_procedure_get(Oid fn_oid, Oid fn_rel, PLyTrigType is_trigger)
                                 72                 :                : {
                                 73                 :                :     bool        use_cache;
                                 74                 :                :     HeapTuple   procTup;
                                 75                 :                :     PLyProcedureKey key;
 4658 tgl@sss.pgh.pa.us          76                 :CBC         951 :     PLyProcedureEntry *volatile entry = NULL;
                                 77                 :            951 :     PLyProcedure *volatile proc = NULL;
                                 78                 :            951 :     bool        found = false;
                                 79                 :                : 
   67 peter@eisentraut.org       80   [ +  +  +  + ]:GNC         951 :     if (is_trigger == PLPY_TRIGGER && fn_rel == InvalidOid)
                                 81                 :             24 :         use_cache = false;
                                 82                 :                :     else
                                 83                 :            927 :         use_cache = true;
                                 84                 :                : 
 5062 peter_e@gmx.net            85                 :CBC         951 :     procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fn_oid));
                                 86         [ -  + ]:            951 :     if (!HeapTupleIsValid(procTup))
 5062 peter_e@gmx.net            87         [ #  # ]:UBC           0 :         elog(ERROR, "cache lookup failed for function %u", fn_oid);
                                 88                 :                : 
                                 89                 :                :     /*
                                 90                 :                :      * Look for the function in the cache, unless we don't have the necessary
                                 91                 :                :      * information (e.g. during validation). In that case we just don't cache
                                 92                 :                :      * anything.
                                 93                 :                :      */
 4658 tgl@sss.pgh.pa.us          94         [ +  + ]:CBC         951 :     if (use_cache)
                                 95                 :                :     {
                                 96                 :            927 :         key.fn_oid = fn_oid;
                                 97                 :            927 :         key.fn_rel = fn_rel;
                                 98                 :            927 :         entry = hash_search(PLy_procedure_cache, &key, HASH_ENTER, &found);
                                 99                 :            927 :         proc = entry->proc;
                                100                 :                :     }
                                101                 :                : 
 5062 peter_e@gmx.net           102         [ +  + ]:            951 :     PG_TRY();
                                103                 :                :     {
                                104         [ +  + ]:            951 :         if (!found)
                                105                 :                :         {
                                106                 :                :             /* Haven't found it, create a new procedure */
 4658 tgl@sss.pgh.pa.us         107                 :            274 :             proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
                                108         [ +  + ]:            270 :             if (use_cache)
                                109                 :            246 :                 entry->proc = proc;
                                110                 :                :             else
                                111                 :                :             {
                                112                 :                :                 /* Delete the proc, otherwise it's a memory leak */
    4 tgl@sss.pgh.pa.us         113                 :GNC          24 :                 PLy_procedure_delete(proc);
                                114                 :             24 :                 proc = NULL;
                                115                 :                :             }
                                116                 :                :         }
 4658 tgl@sss.pgh.pa.us         117         [ +  + ]:CBC         677 :         else if (!PLy_procedure_valid(proc, procTup))
                                118                 :                :         {
                                119                 :                :             /* Found it, but it's invalid, free and reuse the cache entry */
 3644                           120                 :              5 :             entry->proc = NULL;
                                121         [ +  - ]:              5 :             if (proc)
                                122                 :              5 :                 PLy_procedure_delete(proc);
 4658                           123                 :              5 :             proc = PLy_procedure_create(procTup, fn_oid, is_trigger);
                                124                 :              5 :             entry->proc = proc;
                                125                 :                :         }
                                126                 :                :         /* Found it and it's valid, it's fine to use it */
                                127                 :                :     }
 5062 peter_e@gmx.net           128                 :              4 :     PG_CATCH();
                                129                 :                :     {
                                130                 :                :         /* Do not leave an uninitialized entry in the cache */
 4658 tgl@sss.pgh.pa.us         131         [ +  - ]:              4 :         if (use_cache)
                                132                 :              4 :             hash_search(PLy_procedure_cache, &key, HASH_REMOVE, NULL);
 5062 peter_e@gmx.net           133                 :              4 :         PG_RE_THROW();
                                134                 :                :     }
                                135         [ -  + ]:            947 :     PG_END_TRY();
                                136                 :                : 
                                137                 :            947 :     ReleaseSysCache(procTup);
                                138                 :                : 
 4658 tgl@sss.pgh.pa.us         139                 :            947 :     return proc;
                                140                 :                : }
                                141                 :                : 
                                142                 :                : /*
                                143                 :                :  * Create a new PLyProcedure structure
                                144                 :                :  */
                                145                 :                : static PLyProcedure *
   67 peter@eisentraut.org      146                 :GNC         279 : PLy_procedure_create(HeapTuple procTup, Oid fn_oid, PLyTrigType is_trigger)
                                147                 :                : {
                                148                 :                :     char        procName[NAMEDATALEN + 256];
                                149                 :                :     Form_pg_proc procStruct;
                                150                 :                :     PLyProcedure *volatile proc;
                                151                 :                :     MemoryContext cxt;
                                152                 :                :     MemoryContext oldcxt;
                                153                 :                :     int         rv;
                                154                 :                :     char       *ptr;
                                155                 :                : 
 5062 peter_e@gmx.net           156                 :CBC         279 :     procStruct = (Form_pg_proc) GETSTRUCT(procTup);
                                157                 :            558 :     rv = snprintf(procName, sizeof(procName),
                                158                 :                :                   "__plpython_procedure_%s_%u",
                                159                 :            279 :                   NameStr(procStruct->proname),
                                160                 :                :                   fn_oid);
                                161   [ +  -  -  + ]:            279 :     if (rv >= sizeof(procName) || rv < 0)
 5062 peter_e@gmx.net           162         [ #  # ]:UBC           0 :         elog(ERROR, "procedure name would overrun buffer");
                                163                 :                : 
                                164                 :                :     /* Replace any not-legal-in-Python-names characters with '_' */
 3541 tgl@sss.pgh.pa.us         165         [ +  + ]:CBC       13067 :     for (ptr = procName; *ptr; ptr++)
                                166                 :                :     {
                                167   [ +  +  +  + ]:          12788 :         if (!((*ptr >= 'A' && *ptr <= 'Z') ||
                                168   [ +  +  -  + ]:          12787 :               (*ptr >= 'a' && *ptr <= 'z') ||
                                169   [ +  +  +  + ]:           3427 :               (*ptr >= '0' && *ptr <= '9')))
                                170                 :           1930 :             *ptr = '_';
                                171                 :                :     }
                                172                 :                : 
                                173                 :                :     /* Create long-lived context that all procedure info will live in */
 2771                           174                 :            279 :     cxt = AllocSetContextCreate(TopMemoryContext,
                                175                 :                :                                 "PL/Python function",
                                176                 :                :                                 ALLOCSET_DEFAULT_SIZES);
                                177                 :                : 
 3644                           178                 :            279 :     oldcxt = MemoryContextSwitchTo(cxt);
                                179                 :                : 
                                180                 :            279 :     proc = (PLyProcedure *) palloc0(sizeof(PLyProcedure));
                                181                 :            279 :     proc->mcxt = cxt;
                                182                 :                : 
 5062 peter_e@gmx.net           183         [ +  + ]:            279 :     PG_TRY();
                                184                 :                :     {
                                185                 :                :         Datum       protrftypes_datum;
                                186                 :                :         Datum       prosrcdatum;
                                187                 :                :         bool        isnull;
                                188                 :                :         char       *procSource;
                                189                 :                :         int         i;
                                190                 :                : 
 3644 tgl@sss.pgh.pa.us         191                 :            279 :         proc->proname = pstrdup(NameStr(procStruct->proname));
 2771                           192                 :            279 :         MemoryContextSetIdentifier(cxt, proc->proname);
 3644                           193                 :            279 :         proc->pyname = pstrdup(procName);
                                194                 :            279 :         proc->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data);
                                195                 :            279 :         proc->fn_tid = procTup->t_self;
 3492                           196                 :            279 :         proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
                                197                 :            279 :         proc->is_setof = procStruct->proretset;
 2796 peter_e@gmx.net           198                 :            279 :         proc->is_procedure = (procStruct->prokind == PROKIND_PROCEDURE);
  538 tgl@sss.pgh.pa.us         199                 :            279 :         proc->is_trigger = is_trigger;
 3492                           200                 :            279 :         proc->src = NULL;
                                201                 :            279 :         proc->argnames = NULL;
 2902                           202                 :            279 :         proc->args = NULL;
 3644                           203                 :            279 :         proc->nargs = 0;
                                204                 :            279 :         proc->langid = procStruct->prolang;
                                205                 :            279 :         protrftypes_datum = SysCacheGetAttr(PROCOID, procTup,
                                206                 :                :                                             Anum_pg_proc_protrftypes,
                                207                 :                :                                             &isnull);
                                208         [ +  + ]:            279 :         proc->trftypes = isnull ? NIL : oid_array_to_list(protrftypes_datum);
 3492                           209                 :            279 :         proc->code = NULL;
                                210                 :            279 :         proc->statics = NULL;
 3644                           211                 :            279 :         proc->globals = NULL;
 3492                           212                 :            279 :         proc->calldepth = 0;
                                213                 :            279 :         proc->argstack = NULL;
                                214                 :                : 
                                215                 :                :         /*
                                216                 :                :          * get information required for output conversion of the return value,
                                217                 :                :          * but only if this isn't a trigger.
                                218                 :                :          */
   67 peter@eisentraut.org      219         [ +  + ]:GNC         279 :         if (is_trigger == PLPY_NOT_TRIGGER)
                                220                 :                :         {
 2902 tgl@sss.pgh.pa.us         221                 :CBC         228 :             Oid         rettype = procStruct->prorettype;
                                222                 :                :             HeapTuple   rvTypeTup;
                                223                 :                :             Form_pg_type rvTypeStruct;
                                224                 :                : 
                                225                 :            228 :             rvTypeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettype));
 5062 peter_e@gmx.net           226         [ -  + ]:            228 :             if (!HeapTupleIsValid(rvTypeTup))
 2902 tgl@sss.pgh.pa.us         227         [ #  # ]:UBC           0 :                 elog(ERROR, "cache lookup failed for type %u", rettype);
 5062 peter_e@gmx.net           228                 :CBC         228 :             rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
                                229                 :                : 
                                230                 :                :             /* Disallow pseudotype result, except for void or record */
                                231         [ +  + ]:            228 :             if (rvTypeStruct->typtype == TYPTYPE_PSEUDO)
                                232                 :                :             {
 2902 tgl@sss.pgh.pa.us         233   [ +  +  +  + ]:             52 :                 if (rettype == VOIDOID ||
                                234                 :                :                     rettype == RECORDOID)
                                235                 :                :                      /* okay */ ;
 1824                           236   [ -  +  -  - ]:              1 :                 else if (rettype == TRIGGEROID || rettype == EVENT_TRIGGEROID)
 5062 peter_e@gmx.net           237         [ +  - ]:              1 :                     ereport(ERROR,
                                238                 :                :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                239                 :                :                              errmsg("trigger functions can only be called as triggers")));
                                240                 :                :                 else
 5062 peter_e@gmx.net           241         [ #  # ]:UBC           0 :                     ereport(ERROR,
                                242                 :                :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                243                 :                :                              errmsg("PL/Python functions cannot return type %s",
                                244                 :                :                                     format_type_be(rettype))));
                                245                 :                :             }
                                246                 :                : 
                                247                 :                :             /* set up output function for procedure result */
 2902 tgl@sss.pgh.pa.us         248                 :CBC         227 :             PLy_output_setup_func(&proc->result, proc->mcxt,
                                249                 :                :                                   rettype, -1, proc);
                                250                 :                : 
 5062 peter_e@gmx.net           251                 :            227 :             ReleaseSysCache(rvTypeTup);
                                252                 :                :         }
                                253                 :                :         else
                                254                 :                :         {
                                255                 :                :             /*
                                256                 :                :              * In a trigger function, we use proc->result and proc->result_in
                                257                 :                :              * for converting tuples, but we don't yet have enough info to set
                                258                 :                :              * them up.  PLy_exec_trigger will deal with it.
                                259                 :                :              */
 2902 tgl@sss.pgh.pa.us         260                 :             51 :             proc->result.typoid = InvalidOid;
                                261                 :             51 :             proc->result_in.typoid = InvalidOid;
                                262                 :                :         }
                                263                 :                : 
                                264                 :                :         /*
                                265                 :                :          * Now get information required for input conversion of the
                                266                 :                :          * procedure's arguments.  Note that we ignore output arguments here.
                                267                 :                :          * If the function returns record, those I/O functions will be set up
                                268                 :                :          * when the function is first called.
                                269                 :                :          */
 5062 peter_e@gmx.net           270         [ +  + ]:            278 :         if (procStruct->pronargs)
                                271                 :                :         {
                                272                 :                :             Oid        *types;
                                273                 :                :             char      **names,
                                274                 :                :                        *modes;
                                275                 :                :             int         pos,
                                276                 :                :                         total;
                                277                 :                : 
                                278                 :                :             /* extract argument type info from the pg_proc tuple */
                                279                 :            107 :             total = get_func_arg_info(procTup, &types, &names, &modes);
                                280                 :                : 
                                281                 :                :             /* count number of in+inout args into proc->nargs */
                                282         [ +  + ]:            107 :             if (modes == NULL)
                                283                 :             96 :                 proc->nargs = total;
                                284                 :                :             else
                                285                 :                :             {
                                286                 :                :                 /* proc->nargs was initialized to 0 above */
                                287         [ +  + ]:             41 :                 for (i = 0; i < total; i++)
                                288                 :                :                 {
 1600 tgl@sss.pgh.pa.us         289         [ +  + ]:             30 :                     if (modes[i] != PROARGMODE_OUT &&
 5062 peter_e@gmx.net           290         [ +  - ]:             18 :                         modes[i] != PROARGMODE_TABLE)
                                291                 :             18 :                         (proc->nargs)++;
                                292                 :                :                 }
                                293                 :                :             }
                                294                 :                : 
                                295                 :                :             /* Allocate arrays for per-input-argument data */
 3644 tgl@sss.pgh.pa.us         296                 :            107 :             proc->argnames = (char **) palloc0(sizeof(char *) * proc->nargs);
 2902                           297                 :            107 :             proc->args = (PLyDatumToOb *) palloc0(sizeof(PLyDatumToOb) * proc->nargs);
                                298                 :                : 
 5062 peter_e@gmx.net           299         [ +  + ]:            277 :             for (i = pos = 0; i < total; i++)
                                300                 :                :             {
                                301                 :                :                 HeapTuple   argTypeTup;
                                302                 :                :                 Form_pg_type argTypeStruct;
                                303                 :                : 
                                304         [ +  + ]:            170 :                 if (modes &&
 1600 tgl@sss.pgh.pa.us         305         [ +  + ]:             30 :                     (modes[i] == PROARGMODE_OUT ||
 5062 peter_e@gmx.net           306         [ -  + ]:             18 :                      modes[i] == PROARGMODE_TABLE))
                                307                 :             12 :                     continue;   /* skip OUT arguments */
                                308                 :                : 
                                309         [ -  + ]:            158 :                 Assert(types[i] == procStruct->proargtypes.values[pos]);
                                310                 :                : 
                                311                 :            158 :                 argTypeTup = SearchSysCache1(TYPEOID,
                                312                 :            158 :                                              ObjectIdGetDatum(types[i]));
                                313         [ -  + ]:            158 :                 if (!HeapTupleIsValid(argTypeTup))
 5062 peter_e@gmx.net           314         [ #  # ]:UBC           0 :                     elog(ERROR, "cache lookup failed for type %u", types[i]);
 5062 peter_e@gmx.net           315                 :CBC         158 :                 argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup);
                                316                 :                : 
                                317                 :                :                 /* disallow pseudotype arguments */
 2902 tgl@sss.pgh.pa.us         318         [ -  + ]:            158 :                 if (argTypeStruct->typtype == TYPTYPE_PSEUDO)
 2902 tgl@sss.pgh.pa.us         319         [ #  # ]:UBC           0 :                     ereport(ERROR,
                                320                 :                :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                321                 :                :                              errmsg("PL/Python functions cannot accept type %s",
                                322                 :                :                                     format_type_be(types[i]))));
                                323                 :                : 
                                324                 :                :                 /* set up I/O function info */
 2902 tgl@sss.pgh.pa.us         325                 :CBC         158 :                 PLy_input_setup_func(&proc->args[pos], proc->mcxt,
                                326                 :            158 :                                      types[i], -1,  /* typmod not known */
                                327                 :                :                                      proc);
                                328                 :                : 
                                329                 :                :                 /* get argument name */
 3644                           330         [ +  + ]:            158 :                 proc->argnames[pos] = names ? pstrdup(names[i]) : NULL;
                                331                 :                : 
 5062 peter_e@gmx.net           332                 :            158 :                 ReleaseSysCache(argTypeTup);
                                333                 :                : 
                                334                 :            158 :                 pos++;
                                335                 :                :             }
                                336                 :                :         }
                                337                 :                : 
                                338                 :                :         /*
                                339                 :                :          * get the text of the function.
                                340                 :                :          */
  947 dgustafsson@postgres      341                 :            278 :         prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procTup,
                                342                 :                :                                              Anum_pg_proc_prosrc);
 5062 peter_e@gmx.net           343                 :            278 :         procSource = TextDatumGetCString(prosrcdatum);
                                344                 :                : 
                                345                 :            278 :         PLy_procedure_compile(proc, procSource);
                                346                 :                : 
                                347                 :            275 :         pfree(procSource);
                                348                 :                :     }
                                349                 :              4 :     PG_CATCH();
                                350                 :                :     {
 3644 tgl@sss.pgh.pa.us         351                 :              4 :         MemoryContextSwitchTo(oldcxt);
 5062 peter_e@gmx.net           352                 :              4 :         PLy_procedure_delete(proc);
                                353                 :              4 :         PG_RE_THROW();
                                354                 :                :     }
                                355         [ -  + ]:            275 :     PG_END_TRY();
                                356                 :                : 
 3644 tgl@sss.pgh.pa.us         357                 :            275 :     MemoryContextSwitchTo(oldcxt);
 5062 peter_e@gmx.net           358                 :            275 :     return proc;
                                359                 :                : }
                                360                 :                : 
                                361                 :                : /*
                                362                 :                :  * Insert the procedure into the Python interpreter
                                363                 :                :  */
                                364                 :                : void
                                365                 :            299 : PLy_procedure_compile(PLyProcedure *proc, const char *src)
                                366                 :                : {
                                367                 :            299 :     PyObject   *crv = NULL;
                                368                 :                :     char       *msrc;
                                369                 :                :     PyObject   *code0;
                                370                 :                : 
                                371                 :            299 :     proc->globals = PyDict_Copy(PLy_interp_globals);
                                372                 :                : 
                                373                 :                :     /*
                                374                 :                :      * SD is private preserved data between calls. GD is global data shared by
                                375                 :                :      * all functions
                                376                 :                :      */
                                377                 :            299 :     proc->statics = PyDict_New();
 2918                           378         [ -  + ]:            299 :     if (!proc->statics)
 2918 peter_e@gmx.net           379                 :UBC           0 :         PLy_elog(ERROR, NULL);
 5062 peter_e@gmx.net           380                 :CBC         299 :     PyDict_SetItemString(proc->globals, "SD", proc->statics);
                                381                 :                : 
                                382                 :                :     /*
                                383                 :                :      * insert the function code into the interpreter
                                384                 :                :      */
                                385                 :            299 :     msrc = PLy_procedure_munge_source(proc->pyname, src);
                                386                 :                :     /* Save the mangled source for later inclusion in tracebacks */
 3644 tgl@sss.pgh.pa.us         387                 :            299 :     proc->src = MemoryContextStrdup(proc->mcxt, msrc);
  229 peter@eisentraut.org      388                 :            299 :     code0 = Py_CompileString(msrc, "<string>", Py_file_input);
                                389         [ +  + ]:            299 :     if (code0)
                                390                 :            296 :         crv = PyEval_EvalCode(code0, proc->globals, NULL);
 5062 peter_e@gmx.net           391                 :            299 :     pfree(msrc);
                                392                 :                : 
                                393         [ +  + ]:            299 :     if (crv != NULL)
                                394                 :                :     {
                                395                 :                :         int         clen;
                                396                 :                :         char        call[NAMEDATALEN + 256];
                                397                 :                : 
                                398                 :                :         Py_DECREF(crv);
                                399                 :                : 
                                400                 :                :         /*
                                401                 :                :          * compile a call to the function
                                402                 :                :          */
                                403                 :            296 :         clen = snprintf(call, sizeof(call), "%s()", proc->pyname);
                                404   [ +  -  -  + ]:            296 :         if (clen < 0 || clen >= sizeof(call))
 5062 peter_e@gmx.net           405         [ #  # ]:UBC           0 :             elog(ERROR, "string would overflow buffer");
 5062 peter_e@gmx.net           406                 :CBC         296 :         proc->code = Py_CompileString(call, "<string>", Py_eval_input);
                                407         [ +  - ]:            296 :         if (proc->code != NULL)
                                408                 :            296 :             return;
                                409                 :                :     }
                                410                 :                : 
                                411         [ +  - ]:              3 :     if (proc->proname)
                                412                 :              3 :         PLy_elog(ERROR, "could not compile PL/Python function \"%s\"",
                                413                 :                :                  proc->proname);
                                414                 :                :     else
 5062 peter_e@gmx.net           415                 :UBC           0 :         PLy_elog(ERROR, "could not compile anonymous PL/Python code block");
                                416                 :                : }
                                417                 :                : 
                                418                 :                : void
 5062 peter_e@gmx.net           419                 :CBC          54 : PLy_procedure_delete(PLyProcedure *proc)
                                420                 :                : {
                                421                 :             54 :     Py_XDECREF(proc->code);
                                422                 :             54 :     Py_XDECREF(proc->statics);
                                423                 :             54 :     Py_XDECREF(proc->globals);
 3644 tgl@sss.pgh.pa.us         424                 :             54 :     MemoryContextDelete(proc->mcxt);
 5062 peter_e@gmx.net           425                 :             54 : }
                                426                 :                : 
                                427                 :                : /*
                                428                 :                :  * Decide whether a cached PLyProcedure struct is still valid
                                429                 :                :  */
                                430                 :                : static bool
                                431                 :            677 : PLy_procedure_valid(PLyProcedure *proc, HeapTuple procTup)
                                432                 :                : {
 3644 tgl@sss.pgh.pa.us         433         [ -  + ]:            677 :     if (proc == NULL)
 3644 tgl@sss.pgh.pa.us         434                 :UBC           0 :         return false;
                                435                 :                : 
                                436                 :                :     /* If the pg_proc tuple has changed, it's not valid */
 4327 rhaas@postgresql.org      437   [ +  +  -  + ]:CBC        1349 :     if (!(proc->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) &&
 5062 peter_e@gmx.net           438                 :            672 :           ItemPointerEquals(&proc->fn_tid, &procTup->t_self)))
                                439                 :              5 :         return false;
                                440                 :                : 
 2902 tgl@sss.pgh.pa.us         441                 :            672 :     return true;
                                442                 :                : }
                                443                 :                : 
                                444                 :                : static char *
 5062 peter_e@gmx.net           445                 :            299 : PLy_procedure_munge_source(const char *name, const char *src)
                                446                 :                : {
                                447                 :                :     char       *mrc,
                                448                 :                :                *mp;
                                449                 :                :     const char *sp;
                                450                 :                :     size_t      mlen;
                                451                 :                :     int         plen;
                                452                 :                : 
                                453                 :                :     /*
                                454                 :                :      * room for function source and the def statement
                                455                 :                :      */
                                456                 :            299 :     mlen = (strlen(src) * 2) + strlen(name) + 16;
                                457                 :                : 
                                458                 :            299 :     mrc = palloc(mlen);
                                459                 :            299 :     plen = snprintf(mrc, mlen, "def %s():\n\t", name);
                                460   [ +  -  -  + ]:            299 :     Assert(plen >= 0 && plen < mlen);
                                461                 :                : 
                                462                 :            299 :     sp = src;
                                463                 :            299 :     mp = mrc + plen;
                                464                 :                : 
                                465         [ +  + ]:          32181 :     while (*sp != '\0')
                                466                 :                :     {
                                467   [ +  +  +  + ]:          31882 :         if (*sp == '\r' && *(sp + 1) == '\n')
                                468                 :              3 :             sp++;
                                469                 :                : 
                                470   [ +  +  +  + ]:          31882 :         if (*sp == '\n' || *sp == '\r')
                                471                 :                :         {
                                472                 :           1346 :             *mp++ = '\n';
                                473                 :           1346 :             *mp++ = '\t';
                                474                 :           1346 :             sp++;
                                475                 :                :         }
                                476                 :                :         else
                                477                 :          30536 :             *mp++ = *sp++;
                                478                 :                :     }
                                479                 :            299 :     *mp++ = '\n';
                                480                 :            299 :     *mp++ = '\n';
                                481                 :            299 :     *mp = '\0';
                                482                 :                : 
                                483         [ -  + ]:            299 :     if (mp > (mrc + mlen))
 2275 michael@paquier.xyz       484         [ #  # ]:UBC           0 :         elog(FATAL, "buffer overrun in PLy_procedure_munge_source");
                                485                 :                : 
 5062 peter_e@gmx.net           486                 :CBC         299 :     return mrc;
                                487                 :                : }
        

Generated by: LCOV version 2.4-beta