LCOV - code coverage report
Current view: top level - src/pl/plpgsql/src - pl_comp.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 805 871 92.4 %
Date: 2024-04-20 06:11:45 Functions: 39 39 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pl_comp.c        - Compiler part of the PL/pgSQL
       4             :  *            procedural language
       5             :  *
       6             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/pl/plpgsql/src/pl_comp.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : 
      16             : #include "postgres.h"
      17             : 
      18             : #include <ctype.h>
      19             : 
      20             : #include "access/htup_details.h"
      21             : #include "catalog/namespace.h"
      22             : #include "catalog/pg_proc.h"
      23             : #include "catalog/pg_type.h"
      24             : #include "funcapi.h"
      25             : #include "nodes/makefuncs.h"
      26             : #include "parser/parse_type.h"
      27             : #include "plpgsql.h"
      28             : #include "utils/builtins.h"
      29             : #include "utils/fmgroids.h"
      30             : #include "utils/guc.h"
      31             : #include "utils/lsyscache.h"
      32             : #include "utils/memutils.h"
      33             : #include "utils/regproc.h"
      34             : #include "utils/rel.h"
      35             : #include "utils/syscache.h"
      36             : #include "utils/typcache.h"
      37             : 
      38             : /* ----------
      39             :  * Our own local and global variables
      40             :  * ----------
      41             :  */
      42             : PLpgSQL_stmt_block *plpgsql_parse_result;
      43             : 
      44             : static int  datums_alloc;
      45             : int         plpgsql_nDatums;
      46             : PLpgSQL_datum **plpgsql_Datums;
      47             : static int  datums_last;
      48             : 
      49             : char       *plpgsql_error_funcname;
      50             : bool        plpgsql_DumpExecTree = false;
      51             : bool        plpgsql_check_syntax = false;
      52             : 
      53             : PLpgSQL_function *plpgsql_curr_compile;
      54             : 
      55             : /* A context appropriate for short-term allocs during compilation */
      56             : MemoryContext plpgsql_compile_tmp_cxt;
      57             : 
      58             : /* ----------
      59             :  * Hash table for compiled functions
      60             :  * ----------
      61             :  */
      62             : static HTAB *plpgsql_HashTable = NULL;
      63             : 
      64             : typedef struct plpgsql_hashent
      65             : {
      66             :     PLpgSQL_func_hashkey key;
      67             :     PLpgSQL_function *function;
      68             : } plpgsql_HashEnt;
      69             : 
      70             : #define FUNCS_PER_USER      128 /* initial table size */
      71             : 
      72             : /* ----------
      73             :  * Lookup table for EXCEPTION condition names
      74             :  * ----------
      75             :  */
      76             : typedef struct
      77             : {
      78             :     const char *label;
      79             :     int         sqlerrstate;
      80             : } ExceptionLabelMap;
      81             : 
      82             : static const ExceptionLabelMap exception_label_map[] = {
      83             : #include "plerrcodes.h"           /* pgrminclude ignore */
      84             :     {NULL, 0}
      85             : };
      86             : 
      87             : 
      88             : /* ----------
      89             :  * static prototypes
      90             :  * ----------
      91             :  */
      92             : static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo,
      93             :                                     HeapTuple procTup,
      94             :                                     PLpgSQL_function *function,
      95             :                                     PLpgSQL_func_hashkey *hashkey,
      96             :                                     bool forValidator);
      97             : static void plpgsql_compile_error_callback(void *arg);
      98             : static void add_parameter_name(PLpgSQL_nsitem_type itemtype, int itemno, const char *name);
      99             : static void add_dummy_return(PLpgSQL_function *function);
     100             : static Node *plpgsql_pre_column_ref(ParseState *pstate, ColumnRef *cref);
     101             : static Node *plpgsql_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var);
     102             : static Node *plpgsql_param_ref(ParseState *pstate, ParamRef *pref);
     103             : static Node *resolve_column_ref(ParseState *pstate, PLpgSQL_expr *expr,
     104             :                                 ColumnRef *cref, bool error_if_no_field);
     105             : static Node *make_datum_param(PLpgSQL_expr *expr, int dno, int location);
     106             : static PLpgSQL_row *build_row_from_vars(PLpgSQL_variable **vars, int numvars);
     107             : static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod,
     108             :                                     Oid collation, TypeName *origtypname);
     109             : static void plpgsql_start_datums(void);
     110             : static void plpgsql_finish_datums(PLpgSQL_function *function);
     111             : static void compute_function_hashkey(FunctionCallInfo fcinfo,
     112             :                                      Form_pg_proc procStruct,
     113             :                                      PLpgSQL_func_hashkey *hashkey,
     114             :                                      bool forValidator);
     115             : static void plpgsql_resolve_polymorphic_argtypes(int numargs,
     116             :                                                  Oid *argtypes, char *argmodes,
     117             :                                                  Node *call_expr, bool forValidator,
     118             :                                                  const char *proname);
     119             : static PLpgSQL_function *plpgsql_HashTableLookup(PLpgSQL_func_hashkey *func_key);
     120             : static void plpgsql_HashTableInsert(PLpgSQL_function *function,
     121             :                                     PLpgSQL_func_hashkey *func_key);
     122             : static void plpgsql_HashTableDelete(PLpgSQL_function *function);
     123             : static void delete_function(PLpgSQL_function *func);
     124             : 
     125             : /* ----------
     126             :  * plpgsql_compile      Make an execution tree for a PL/pgSQL function.
     127             :  *
     128             :  * If forValidator is true, we're only compiling for validation purposes,
     129             :  * and so some checks are skipped.
     130             :  *
     131             :  * Note: it's important for this to fall through quickly if the function
     132             :  * has already been compiled.
     133             :  * ----------
     134             :  */
     135             : PLpgSQL_function *
     136       85040 : plpgsql_compile(FunctionCallInfo fcinfo, bool forValidator)
     137             : {
     138       85040 :     Oid         funcOid = fcinfo->flinfo->fn_oid;
     139             :     HeapTuple   procTup;
     140             :     Form_pg_proc procStruct;
     141             :     PLpgSQL_function *function;
     142             :     PLpgSQL_func_hashkey hashkey;
     143       85040 :     bool        function_valid = false;
     144       85040 :     bool        hashkey_valid = false;
     145             : 
     146             :     /*
     147             :      * Lookup the pg_proc tuple by Oid; we'll need it in any case
     148             :      */
     149       85040 :     procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
     150       85040 :     if (!HeapTupleIsValid(procTup))
     151           0 :         elog(ERROR, "cache lookup failed for function %u", funcOid);
     152       85040 :     procStruct = (Form_pg_proc) GETSTRUCT(procTup);
     153             : 
     154             :     /*
     155             :      * See if there's already a cache entry for the current FmgrInfo. If not,
     156             :      * try to find one in the hash table.
     157             :      */
     158       85040 :     function = (PLpgSQL_function *) fcinfo->flinfo->fn_extra;
     159             : 
     160       85040 : recheck:
     161       85040 :     if (!function)
     162             :     {
     163             :         /* Compute hashkey using function signature and actual arg types */
     164       31440 :         compute_function_hashkey(fcinfo, procStruct, &hashkey, forValidator);
     165       31440 :         hashkey_valid = true;
     166             : 
     167             :         /* And do the lookup */
     168       31440 :         function = plpgsql_HashTableLookup(&hashkey);
     169             :     }
     170             : 
     171       85040 :     if (function)
     172             :     {
     173             :         /* We have a compiled function, but is it still valid? */
     174      155418 :         if (function->fn_xmin == HeapTupleHeaderGetRawXmin(procTup->t_data) &&
     175       77378 :             ItemPointerEquals(&function->fn_tid, &procTup->t_self))
     176       77372 :             function_valid = true;
     177             :         else
     178             :         {
     179             :             /*
     180             :              * Nope, so remove it from hashtable and try to drop associated
     181             :              * storage (if not done already).
     182             :              */
     183         668 :             delete_function(function);
     184             : 
     185             :             /*
     186             :              * If the function isn't in active use then we can overwrite the
     187             :              * func struct with new data, allowing any other existing fn_extra
     188             :              * pointers to make use of the new definition on their next use.
     189             :              * If it is in use then just leave it alone and make a new one.
     190             :              * (The active invocations will run to completion using the
     191             :              * previous definition, and then the cache entry will just be
     192             :              * leaked; doesn't seem worth adding code to clean it up, given
     193             :              * what a corner case this is.)
     194             :              *
     195             :              * If we found the function struct via fn_extra then it's possible
     196             :              * a replacement has already been made, so go back and recheck the
     197             :              * hashtable.
     198             :              */
     199         668 :             if (function->use_count != 0)
     200             :             {
     201           0 :                 function = NULL;
     202           0 :                 if (!hashkey_valid)
     203           0 :                     goto recheck;
     204             :             }
     205             :         }
     206             :     }
     207             : 
     208             :     /*
     209             :      * If the function wasn't found or was out-of-date, we have to compile it
     210             :      */
     211       85040 :     if (!function_valid)
     212             :     {
     213             :         /*
     214             :          * Calculate hashkey if we didn't already; we'll need it to store the
     215             :          * completed function.
     216             :          */
     217        7668 :         if (!hashkey_valid)
     218           0 :             compute_function_hashkey(fcinfo, procStruct, &hashkey,
     219             :                                      forValidator);
     220             : 
     221             :         /*
     222             :          * Do the hard part.
     223             :          */
     224        7668 :         function = do_compile(fcinfo, procTup, function,
     225             :                               &hashkey, forValidator);
     226             :     }
     227             : 
     228       84918 :     ReleaseSysCache(procTup);
     229             : 
     230             :     /*
     231             :      * Save pointer in FmgrInfo to avoid search on subsequent calls
     232             :      */
     233       84918 :     fcinfo->flinfo->fn_extra = (void *) function;
     234             : 
     235             :     /*
     236             :      * Finally return the compiled function
     237             :      */
     238       84918 :     return function;
     239             : }
     240             : 
     241             : /*
     242             :  * This is the slow part of plpgsql_compile().
     243             :  *
     244             :  * The passed-in "function" pointer is either NULL or an already-allocated
     245             :  * function struct to overwrite.
     246             :  *
     247             :  * While compiling a function, the CurrentMemoryContext is the
     248             :  * per-function memory context of the function we are compiling. That
     249             :  * means a palloc() will allocate storage with the same lifetime as
     250             :  * the function itself.
     251             :  *
     252             :  * Because palloc()'d storage will not be immediately freed, temporary
     253             :  * allocations should either be performed in a short-lived memory
     254             :  * context or explicitly pfree'd. Since not all backend functions are
     255             :  * careful about pfree'ing their allocations, it is also wise to
     256             :  * switch into a short-term context before calling into the
     257             :  * backend. An appropriate context for performing short-term
     258             :  * allocations is the plpgsql_compile_tmp_cxt.
     259             :  *
     260             :  * NB: this code is not re-entrant.  We assume that nothing we do here could
     261             :  * result in the invocation of another plpgsql function.
     262             :  */
     263             : static PLpgSQL_function *
     264        7668 : do_compile(FunctionCallInfo fcinfo,
     265             :            HeapTuple procTup,
     266             :            PLpgSQL_function *function,
     267             :            PLpgSQL_func_hashkey *hashkey,
     268             :            bool forValidator)
     269             : {
     270        7668 :     Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
     271        7668 :     bool        is_dml_trigger = CALLED_AS_TRIGGER(fcinfo);
     272        7668 :     bool        is_event_trigger = CALLED_AS_EVENT_TRIGGER(fcinfo);
     273             :     Datum       prosrcdatum;
     274             :     char       *proc_source;
     275             :     HeapTuple   typeTup;
     276             :     Form_pg_type typeStruct;
     277             :     PLpgSQL_variable *var;
     278             :     PLpgSQL_rec *rec;
     279             :     int         i;
     280             :     ErrorContextCallback plerrcontext;
     281             :     int         parse_rc;
     282             :     Oid         rettypeid;
     283             :     int         numargs;
     284        7668 :     int         num_in_args = 0;
     285        7668 :     int         num_out_args = 0;
     286             :     Oid        *argtypes;
     287             :     char      **argnames;
     288             :     char       *argmodes;
     289        7668 :     int        *in_arg_varnos = NULL;
     290             :     PLpgSQL_variable **out_arg_variables;
     291             :     MemoryContext func_cxt;
     292             : 
     293             :     /*
     294             :      * Setup the scanner input and error info.  We assume that this function
     295             :      * cannot be invoked recursively, so there's no need to save and restore
     296             :      * the static variables used here.
     297             :      */
     298        7668 :     prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procTup, Anum_pg_proc_prosrc);
     299        7668 :     proc_source = TextDatumGetCString(prosrcdatum);
     300        7668 :     plpgsql_scanner_init(proc_source);
     301             : 
     302        7668 :     plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));
     303             : 
     304             :     /*
     305             :      * Setup error traceback support for ereport()
     306             :      */
     307        7668 :     plerrcontext.callback = plpgsql_compile_error_callback;
     308        7668 :     plerrcontext.arg = forValidator ? proc_source : NULL;
     309        7668 :     plerrcontext.previous = error_context_stack;
     310        7668 :     error_context_stack = &plerrcontext;
     311             : 
     312             :     /*
     313             :      * Do extra syntax checks when validating the function definition. We skip
     314             :      * this when actually compiling functions for execution, for performance
     315             :      * reasons.
     316             :      */
     317        7668 :     plpgsql_check_syntax = forValidator;
     318             : 
     319             :     /*
     320             :      * Create the new function struct, if not done already.  The function
     321             :      * structs are never thrown away, so keep them in TopMemoryContext.
     322             :      */
     323        7668 :     if (function == NULL)
     324             :     {
     325             :         function = (PLpgSQL_function *)
     326        7000 :             MemoryContextAllocZero(TopMemoryContext, sizeof(PLpgSQL_function));
     327             :     }
     328             :     else
     329             :     {
     330             :         /* re-using a previously existing struct, so clear it out */
     331         668 :         memset(function, 0, sizeof(PLpgSQL_function));
     332             :     }
     333        7668 :     plpgsql_curr_compile = function;
     334             : 
     335             :     /*
     336             :      * All the permanent output of compilation (e.g. parse tree) is kept in a
     337             :      * per-function memory context, so it can be reclaimed easily.
     338             :      */
     339        7668 :     func_cxt = AllocSetContextCreate(TopMemoryContext,
     340             :                                      "PL/pgSQL function",
     341             :                                      ALLOCSET_DEFAULT_SIZES);
     342        7668 :     plpgsql_compile_tmp_cxt = MemoryContextSwitchTo(func_cxt);
     343             : 
     344        7668 :     function->fn_signature = format_procedure(fcinfo->flinfo->fn_oid);
     345        7668 :     MemoryContextSetIdentifier(func_cxt, function->fn_signature);
     346        7668 :     function->fn_oid = fcinfo->flinfo->fn_oid;
     347        7668 :     function->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data);
     348        7668 :     function->fn_tid = procTup->t_self;
     349        7668 :     function->fn_input_collation = fcinfo->fncollation;
     350        7668 :     function->fn_cxt = func_cxt;
     351        7668 :     function->out_param_varno = -1; /* set up for no OUT param */
     352        7668 :     function->resolve_option = plpgsql_variable_conflict;
     353        7668 :     function->print_strict_params = plpgsql_print_strict_params;
     354             :     /* only promote extra warnings and errors at CREATE FUNCTION time */
     355        7668 :     function->extra_warnings = forValidator ? plpgsql_extra_warnings : 0;
     356        7668 :     function->extra_errors = forValidator ? plpgsql_extra_errors : 0;
     357             : 
     358        7668 :     if (is_dml_trigger)
     359        3576 :         function->fn_is_trigger = PLPGSQL_DML_TRIGGER;
     360        4092 :     else if (is_event_trigger)
     361         418 :         function->fn_is_trigger = PLPGSQL_EVENT_TRIGGER;
     362             :     else
     363        3674 :         function->fn_is_trigger = PLPGSQL_NOT_TRIGGER;
     364             : 
     365        7668 :     function->fn_prokind = procStruct->prokind;
     366             : 
     367        7668 :     function->nstatements = 0;
     368        7668 :     function->requires_procedure_resowner = false;
     369             : 
     370             :     /*
     371             :      * Initialize the compiler, particularly the namespace stack.  The
     372             :      * outermost namespace contains function parameters and other special
     373             :      * variables (such as FOUND), and is named after the function itself.
     374             :      */
     375        7668 :     plpgsql_ns_init();
     376        7668 :     plpgsql_ns_push(NameStr(procStruct->proname), PLPGSQL_LABEL_BLOCK);
     377        7668 :     plpgsql_DumpExecTree = false;
     378        7668 :     plpgsql_start_datums();
     379             : 
     380        7668 :     switch (function->fn_is_trigger)
     381             :     {
     382        3674 :         case PLPGSQL_NOT_TRIGGER:
     383             : 
     384             :             /*
     385             :              * Fetch info about the procedure's parameters. Allocations aren't
     386             :              * needed permanently, so make them in tmp cxt.
     387             :              *
     388             :              * We also need to resolve any polymorphic input or output
     389             :              * argument types.  In validation mode we won't be able to, so we
     390             :              * arbitrarily assume we are dealing with integers.
     391             :              */
     392        3674 :             MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
     393             : 
     394        3674 :             numargs = get_func_arg_info(procTup,
     395             :                                         &argtypes, &argnames, &argmodes);
     396             : 
     397        3674 :             plpgsql_resolve_polymorphic_argtypes(numargs, argtypes, argmodes,
     398        3674 :                                                  fcinfo->flinfo->fn_expr,
     399             :                                                  forValidator,
     400             :                                                  plpgsql_error_funcname);
     401             : 
     402        3674 :             in_arg_varnos = (int *) palloc(numargs * sizeof(int));
     403        3674 :             out_arg_variables = (PLpgSQL_variable **) palloc(numargs * sizeof(PLpgSQL_variable *));
     404             : 
     405        3674 :             MemoryContextSwitchTo(func_cxt);
     406             : 
     407             :             /*
     408             :              * Create the variables for the procedure's parameters.
     409             :              */
     410        8032 :             for (i = 0; i < numargs; i++)
     411             :             {
     412             :                 char        buf[32];
     413        4364 :                 Oid         argtypeid = argtypes[i];
     414        4364 :                 char        argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
     415             :                 PLpgSQL_type *argdtype;
     416             :                 PLpgSQL_variable *argvariable;
     417             :                 PLpgSQL_nsitem_type argitemtype;
     418             : 
     419             :                 /* Create $n name for variable */
     420        4364 :                 snprintf(buf, sizeof(buf), "$%d", i + 1);
     421             : 
     422             :                 /* Create datatype info */
     423        4364 :                 argdtype = plpgsql_build_datatype(argtypeid,
     424             :                                                   -1,
     425             :                                                   function->fn_input_collation,
     426             :                                                   NULL);
     427             : 
     428             :                 /* Disallow pseudotype argument */
     429             :                 /* (note we already replaced polymorphic types) */
     430             :                 /* (build_variable would do this, but wrong message) */
     431        4364 :                 if (argdtype->ttype == PLPGSQL_TTYPE_PSEUDO)
     432           6 :                     ereport(ERROR,
     433             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     434             :                              errmsg("PL/pgSQL functions cannot accept type %s",
     435             :                                     format_type_be(argtypeid))));
     436             : 
     437             :                 /*
     438             :                  * Build variable and add to datum list.  If there's a name
     439             :                  * for the argument, use that as refname, else use $n name.
     440             :                  */
     441        7642 :                 argvariable = plpgsql_build_variable((argnames &&
     442        3284 :                                                       argnames[i][0] != '\0') ?
     443        3266 :                                                      argnames[i] : buf,
     444             :                                                      0, argdtype, false);
     445             : 
     446        4358 :                 if (argvariable->dtype == PLPGSQL_DTYPE_VAR)
     447             :                 {
     448        4306 :                     argitemtype = PLPGSQL_NSTYPE_VAR;
     449             :                 }
     450             :                 else
     451             :                 {
     452             :                     Assert(argvariable->dtype == PLPGSQL_DTYPE_REC);
     453          52 :                     argitemtype = PLPGSQL_NSTYPE_REC;
     454             :                 }
     455             : 
     456             :                 /* Remember arguments in appropriate arrays */
     457        4358 :                 if (argmode == PROARGMODE_IN ||
     458         430 :                     argmode == PROARGMODE_INOUT ||
     459             :                     argmode == PROARGMODE_VARIADIC)
     460        3942 :                     in_arg_varnos[num_in_args++] = argvariable->dno;
     461        4358 :                 if (argmode == PROARGMODE_OUT ||
     462        4038 :                     argmode == PROARGMODE_INOUT ||
     463             :                     argmode == PROARGMODE_TABLE)
     464         464 :                     out_arg_variables[num_out_args++] = argvariable;
     465             : 
     466             :                 /* Add to namespace under the $n name */
     467        4358 :                 add_parameter_name(argitemtype, argvariable->dno, buf);
     468             : 
     469             :                 /* If there's a name for the argument, make an alias */
     470        4358 :                 if (argnames && argnames[i][0] != '\0')
     471        3266 :                     add_parameter_name(argitemtype, argvariable->dno,
     472        3266 :                                        argnames[i]);
     473             :             }
     474             : 
     475             :             /*
     476             :              * If there's just one OUT parameter, out_param_varno points
     477             :              * directly to it.  If there's more than one, build a row that
     478             :              * holds all of them.  Procedures return a row even for one OUT
     479             :              * parameter.
     480             :              */
     481        3668 :             if (num_out_args > 1 ||
     482          78 :                 (num_out_args == 1 && function->fn_prokind == PROKIND_PROCEDURE))
     483         182 :             {
     484         182 :                 PLpgSQL_row *row = build_row_from_vars(out_arg_variables,
     485             :                                                        num_out_args);
     486             : 
     487         182 :                 plpgsql_adddatum((PLpgSQL_datum *) row);
     488         182 :                 function->out_param_varno = row->dno;
     489             :             }
     490        3486 :             else if (num_out_args == 1)
     491          60 :                 function->out_param_varno = out_arg_variables[0]->dno;
     492             : 
     493             :             /*
     494             :              * Check for a polymorphic returntype. If found, use the actual
     495             :              * returntype type from the caller's FuncExpr node, if we have
     496             :              * one.  (In validation mode we arbitrarily assume we are dealing
     497             :              * with integers.)
     498             :              *
     499             :              * Note: errcode is FEATURE_NOT_SUPPORTED because it should always
     500             :              * work; if it doesn't we're in some context that fails to make
     501             :              * the info available.
     502             :              */
     503        3668 :             rettypeid = procStruct->prorettype;
     504        3668 :             if (IsPolymorphicType(rettypeid))
     505             :             {
     506         144 :                 if (forValidator)
     507             :                 {
     508          72 :                     if (rettypeid == ANYARRAYOID ||
     509             :                         rettypeid == ANYCOMPATIBLEARRAYOID)
     510          48 :                         rettypeid = INT4ARRAYOID;
     511          24 :                     else if (rettypeid == ANYRANGEOID ||
     512             :                              rettypeid == ANYCOMPATIBLERANGEOID)
     513           6 :                         rettypeid = INT4RANGEOID;
     514          18 :                     else if (rettypeid == ANYMULTIRANGEOID)
     515           6 :                         rettypeid = INT4MULTIRANGEOID;
     516             :                     else        /* ANYELEMENT or ANYNONARRAY or ANYCOMPATIBLE */
     517          12 :                         rettypeid = INT4OID;
     518             :                     /* XXX what could we use for ANYENUM? */
     519             :                 }
     520             :                 else
     521             :                 {
     522          72 :                     rettypeid = get_fn_expr_rettype(fcinfo->flinfo);
     523          72 :                     if (!OidIsValid(rettypeid))
     524           0 :                         ereport(ERROR,
     525             :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     526             :                                  errmsg("could not determine actual return type "
     527             :                                         "for polymorphic function \"%s\"",
     528             :                                         plpgsql_error_funcname)));
     529             :                 }
     530             :             }
     531             : 
     532             :             /*
     533             :              * Normal function has a defined returntype
     534             :              */
     535        3668 :             function->fn_rettype = rettypeid;
     536        3668 :             function->fn_retset = procStruct->proretset;
     537             : 
     538             :             /*
     539             :              * Lookup the function's return type
     540             :              */
     541        3668 :             typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettypeid));
     542        3668 :             if (!HeapTupleIsValid(typeTup))
     543           0 :                 elog(ERROR, "cache lookup failed for type %u", rettypeid);
     544        3668 :             typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
     545             : 
     546             :             /* Disallow pseudotype result, except VOID or RECORD */
     547             :             /* (note we already replaced polymorphic types) */
     548        3668 :             if (typeStruct->typtype == TYPTYPE_PSEUDO)
     549             :             {
     550        1358 :                 if (rettypeid == VOIDOID ||
     551             :                     rettypeid == RECORDOID)
     552             :                      /* okay */ ;
     553           6 :                 else if (rettypeid == TRIGGEROID || rettypeid == EVENT_TRIGGEROID)
     554           6 :                     ereport(ERROR,
     555             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     556             :                              errmsg("trigger functions can only be called as triggers")));
     557             :                 else
     558           0 :                     ereport(ERROR,
     559             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     560             :                              errmsg("PL/pgSQL functions cannot return type %s",
     561             :                                     format_type_be(rettypeid))));
     562             :             }
     563             : 
     564        3662 :             function->fn_retistuple = type_is_rowtype(rettypeid);
     565        3662 :             function->fn_retisdomain = (typeStruct->typtype == TYPTYPE_DOMAIN);
     566        3662 :             function->fn_retbyval = typeStruct->typbyval;
     567        3662 :             function->fn_rettyplen = typeStruct->typlen;
     568             : 
     569             :             /*
     570             :              * install $0 reference, but only for polymorphic return types,
     571             :              * and not when the return is specified through an output
     572             :              * parameter.
     573             :              */
     574        3662 :             if (IsPolymorphicType(procStruct->prorettype) &&
     575             :                 num_out_args == 0)
     576             :             {
     577         144 :                 (void) plpgsql_build_variable("$0", 0,
     578             :                                               build_datatype(typeTup,
     579             :                                                              -1,
     580             :                                                              function->fn_input_collation,
     581             :                                                              NULL),
     582             :                                               true);
     583             :             }
     584             : 
     585        3662 :             ReleaseSysCache(typeTup);
     586        3662 :             break;
     587             : 
     588        3576 :         case PLPGSQL_DML_TRIGGER:
     589             :             /* Trigger procedure's return type is unknown yet */
     590        3576 :             function->fn_rettype = InvalidOid;
     591        3576 :             function->fn_retbyval = false;
     592        3576 :             function->fn_retistuple = true;
     593        3576 :             function->fn_retisdomain = false;
     594        3576 :             function->fn_retset = false;
     595             : 
     596             :             /* shouldn't be any declared arguments */
     597        3576 :             if (procStruct->pronargs != 0)
     598           0 :                 ereport(ERROR,
     599             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     600             :                          errmsg("trigger functions cannot have declared arguments"),
     601             :                          errhint("The arguments of the trigger can be accessed through TG_NARGS and TG_ARGV instead.")));
     602             : 
     603             :             /* Add the record for referencing NEW ROW */
     604        3576 :             rec = plpgsql_build_record("new", 0, NULL, RECORDOID, true);
     605        3576 :             function->new_varno = rec->dno;
     606             : 
     607             :             /* Add the record for referencing OLD ROW */
     608        3576 :             rec = plpgsql_build_record("old", 0, NULL, RECORDOID, true);
     609        3576 :             function->old_varno = rec->dno;
     610             : 
     611             :             /* Add the variable tg_name */
     612        3576 :             var = plpgsql_build_variable("tg_name", 0,
     613             :                                          plpgsql_build_datatype(NAMEOID,
     614             :                                                                 -1,
     615             :                                                                 function->fn_input_collation,
     616             :                                                                 NULL),
     617             :                                          true);
     618             :             Assert(var->dtype == PLPGSQL_DTYPE_VAR);
     619        3576 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     620        3576 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_NAME;
     621             : 
     622             :             /* Add the variable tg_when */
     623        3576 :             var = plpgsql_build_variable("tg_when", 0,
     624             :                                          plpgsql_build_datatype(TEXTOID,
     625             :                                                                 -1,
     626             :                                                                 function->fn_input_collation,
     627             :                                                                 NULL),
     628             :                                          true);
     629             :             Assert(var->dtype == PLPGSQL_DTYPE_VAR);
     630        3576 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     631        3576 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_WHEN;
     632             : 
     633             :             /* Add the variable tg_level */
     634        3576 :             var = plpgsql_build_variable("tg_level", 0,
     635             :                                          plpgsql_build_datatype(TEXTOID,
     636             :                                                                 -1,
     637             :                                                                 function->fn_input_collation,
     638             :                                                                 NULL),
     639             :                                          true);
     640             :             Assert(var->dtype == PLPGSQL_DTYPE_VAR);
     641        3576 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     642        3576 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_LEVEL;
     643             : 
     644             :             /* Add the variable tg_op */
     645        3576 :             var = plpgsql_build_variable("tg_op", 0,
     646             :                                          plpgsql_build_datatype(TEXTOID,
     647             :                                                                 -1,
     648             :                                                                 function->fn_input_collation,
     649             :                                                                 NULL),
     650             :                                          true);
     651             :             Assert(var->dtype == PLPGSQL_DTYPE_VAR);
     652        3576 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     653        3576 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_OP;
     654             : 
     655             :             /* Add the variable tg_relid */
     656        3576 :             var = plpgsql_build_variable("tg_relid", 0,
     657             :                                          plpgsql_build_datatype(OIDOID,
     658             :                                                                 -1,
     659             :                                                                 InvalidOid,
     660             :                                                                 NULL),
     661             :                                          true);
     662             :             Assert(var->dtype == PLPGSQL_DTYPE_VAR);
     663        3576 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     664        3576 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_RELID;
     665             : 
     666             :             /* Add the variable tg_relname */
     667        3576 :             var = plpgsql_build_variable("tg_relname", 0,
     668             :                                          plpgsql_build_datatype(NAMEOID,
     669             :                                                                 -1,
     670             :                                                                 function->fn_input_collation,
     671             :                                                                 NULL),
     672             :                                          true);
     673             :             Assert(var->dtype == PLPGSQL_DTYPE_VAR);
     674        3576 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     675        3576 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_TABLE_NAME;
     676             : 
     677             :             /* tg_table_name is now preferred to tg_relname */
     678        3576 :             var = plpgsql_build_variable("tg_table_name", 0,
     679             :                                          plpgsql_build_datatype(NAMEOID,
     680             :                                                                 -1,
     681             :                                                                 function->fn_input_collation,
     682             :                                                                 NULL),
     683             :                                          true);
     684             :             Assert(var->dtype == PLPGSQL_DTYPE_VAR);
     685        3576 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     686        3576 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_TABLE_NAME;
     687             : 
     688             :             /* add the variable tg_table_schema */
     689        3576 :             var = plpgsql_build_variable("tg_table_schema", 0,
     690             :                                          plpgsql_build_datatype(NAMEOID,
     691             :                                                                 -1,
     692             :                                                                 function->fn_input_collation,
     693             :                                                                 NULL),
     694             :                                          true);
     695             :             Assert(var->dtype == PLPGSQL_DTYPE_VAR);
     696        3576 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     697        3576 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_TABLE_SCHEMA;
     698             : 
     699             :             /* Add the variable tg_nargs */
     700        3576 :             var = plpgsql_build_variable("tg_nargs", 0,
     701             :                                          plpgsql_build_datatype(INT4OID,
     702             :                                                                 -1,
     703             :                                                                 InvalidOid,
     704             :                                                                 NULL),
     705             :                                          true);
     706             :             Assert(var->dtype == PLPGSQL_DTYPE_VAR);
     707        3576 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     708        3576 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_NARGS;
     709             : 
     710             :             /* Add the variable tg_argv */
     711        3576 :             var = plpgsql_build_variable("tg_argv", 0,
     712             :                                          plpgsql_build_datatype(TEXTARRAYOID,
     713             :                                                                 -1,
     714             :                                                                 function->fn_input_collation,
     715             :                                                                 NULL),
     716             :                                          true);
     717             :             Assert(var->dtype == PLPGSQL_DTYPE_VAR);
     718        3576 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     719        3576 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_ARGV;
     720             : 
     721        3576 :             break;
     722             : 
     723         418 :         case PLPGSQL_EVENT_TRIGGER:
     724         418 :             function->fn_rettype = VOIDOID;
     725         418 :             function->fn_retbyval = false;
     726         418 :             function->fn_retistuple = true;
     727         418 :             function->fn_retisdomain = false;
     728         418 :             function->fn_retset = false;
     729             : 
     730             :             /* shouldn't be any declared arguments */
     731         418 :             if (procStruct->pronargs != 0)
     732           6 :                 ereport(ERROR,
     733             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     734             :                          errmsg("event trigger functions cannot have declared arguments")));
     735             : 
     736             :             /* Add the variable tg_event */
     737         412 :             var = plpgsql_build_variable("tg_event", 0,
     738             :                                          plpgsql_build_datatype(TEXTOID,
     739             :                                                                 -1,
     740             :                                                                 function->fn_input_collation,
     741             :                                                                 NULL),
     742             :                                          true);
     743             :             Assert(var->dtype == PLPGSQL_DTYPE_VAR);
     744         412 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     745         412 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_EVENT;
     746             : 
     747             :             /* Add the variable tg_tag */
     748         412 :             var = plpgsql_build_variable("tg_tag", 0,
     749             :                                          plpgsql_build_datatype(TEXTOID,
     750             :                                                                 -1,
     751             :                                                                 function->fn_input_collation,
     752             :                                                                 NULL),
     753             :                                          true);
     754             :             Assert(var->dtype == PLPGSQL_DTYPE_VAR);
     755         412 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     756         412 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_TAG;
     757             : 
     758         412 :             break;
     759             : 
     760           0 :         default:
     761           0 :             elog(ERROR, "unrecognized function typecode: %d",
     762             :                  (int) function->fn_is_trigger);
     763             :             break;
     764             :     }
     765             : 
     766             :     /* Remember if function is STABLE/IMMUTABLE */
     767        7650 :     function->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
     768             : 
     769             :     /*
     770             :      * Create the magic FOUND variable.
     771             :      */
     772        7650 :     var = plpgsql_build_variable("found", 0,
     773             :                                  plpgsql_build_datatype(BOOLOID,
     774             :                                                         -1,
     775             :                                                         InvalidOid,
     776             :                                                         NULL),
     777             :                                  true);
     778        7650 :     function->found_varno = var->dno;
     779             : 
     780             :     /*
     781             :      * Now parse the function's text
     782             :      */
     783        7650 :     parse_rc = plpgsql_yyparse();
     784        7546 :     if (parse_rc != 0)
     785           0 :         elog(ERROR, "plpgsql parser returned %d", parse_rc);
     786        7546 :     function->action = plpgsql_parse_result;
     787             : 
     788        7546 :     plpgsql_scanner_finish();
     789        7546 :     pfree(proc_source);
     790             : 
     791             :     /*
     792             :      * If it has OUT parameters or returns VOID or returns a set, we allow
     793             :      * control to fall off the end without an explicit RETURN statement. The
     794             :      * easiest way to implement this is to add a RETURN statement to the end
     795             :      * of the statement list during parsing.
     796             :      */
     797        7546 :     if (num_out_args > 0 || function->fn_rettype == VOIDOID ||
     798        5844 :         function->fn_retset)
     799        1950 :         add_dummy_return(function);
     800             : 
     801             :     /*
     802             :      * Complete the function's info
     803             :      */
     804        7546 :     function->fn_nargs = procStruct->pronargs;
     805       11456 :     for (i = 0; i < function->fn_nargs; i++)
     806        3910 :         function->fn_argvarnos[i] = in_arg_varnos[i];
     807             : 
     808        7546 :     plpgsql_finish_datums(function);
     809             : 
     810             :     /* Debug dump for completed functions */
     811        7546 :     if (plpgsql_DumpExecTree)
     812           0 :         plpgsql_dumptree(function);
     813             : 
     814             :     /*
     815             :      * add it to the hash table
     816             :      */
     817        7546 :     plpgsql_HashTableInsert(function, hashkey);
     818             : 
     819             :     /*
     820             :      * Pop the error context stack
     821             :      */
     822        7546 :     error_context_stack = plerrcontext.previous;
     823        7546 :     plpgsql_error_funcname = NULL;
     824             : 
     825        7546 :     plpgsql_check_syntax = false;
     826             : 
     827        7546 :     MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
     828        7546 :     plpgsql_compile_tmp_cxt = NULL;
     829        7546 :     return function;
     830             : }
     831             : 
     832             : /* ----------
     833             :  * plpgsql_compile_inline   Make an execution tree for an anonymous code block.
     834             :  *
     835             :  * Note: this is generally parallel to do_compile(); is it worth trying to
     836             :  * merge the two?
     837             :  *
     838             :  * Note: we assume the block will be thrown away so there is no need to build
     839             :  * persistent data structures.
     840             :  * ----------
     841             :  */
     842             : PLpgSQL_function *
     843        1000 : plpgsql_compile_inline(char *proc_source)
     844             : {
     845        1000 :     char       *func_name = "inline_code_block";
     846             :     PLpgSQL_function *function;
     847             :     ErrorContextCallback plerrcontext;
     848             :     PLpgSQL_variable *var;
     849             :     int         parse_rc;
     850             :     MemoryContext func_cxt;
     851             : 
     852             :     /*
     853             :      * Setup the scanner input and error info.  We assume that this function
     854             :      * cannot be invoked recursively, so there's no need to save and restore
     855             :      * the static variables used here.
     856             :      */
     857        1000 :     plpgsql_scanner_init(proc_source);
     858             : 
     859        1000 :     plpgsql_error_funcname = func_name;
     860             : 
     861             :     /*
     862             :      * Setup error traceback support for ereport()
     863             :      */
     864        1000 :     plerrcontext.callback = plpgsql_compile_error_callback;
     865        1000 :     plerrcontext.arg = proc_source;
     866        1000 :     plerrcontext.previous = error_context_stack;
     867        1000 :     error_context_stack = &plerrcontext;
     868             : 
     869             :     /* Do extra syntax checking if check_function_bodies is on */
     870        1000 :     plpgsql_check_syntax = check_function_bodies;
     871             : 
     872             :     /* Function struct does not live past current statement */
     873        1000 :     function = (PLpgSQL_function *) palloc0(sizeof(PLpgSQL_function));
     874             : 
     875        1000 :     plpgsql_curr_compile = function;
     876             : 
     877             :     /*
     878             :      * All the rest of the compile-time storage (e.g. parse tree) is kept in
     879             :      * its own memory context, so it can be reclaimed easily.
     880             :      */
     881        1000 :     func_cxt = AllocSetContextCreate(CurrentMemoryContext,
     882             :                                      "PL/pgSQL inline code context",
     883             :                                      ALLOCSET_DEFAULT_SIZES);
     884        1000 :     plpgsql_compile_tmp_cxt = MemoryContextSwitchTo(func_cxt);
     885             : 
     886        1000 :     function->fn_signature = pstrdup(func_name);
     887        1000 :     function->fn_is_trigger = PLPGSQL_NOT_TRIGGER;
     888        1000 :     function->fn_input_collation = InvalidOid;
     889        1000 :     function->fn_cxt = func_cxt;
     890        1000 :     function->out_param_varno = -1; /* set up for no OUT param */
     891        1000 :     function->resolve_option = plpgsql_variable_conflict;
     892        1000 :     function->print_strict_params = plpgsql_print_strict_params;
     893             : 
     894             :     /*
     895             :      * don't do extra validation for inline code as we don't want to add spam
     896             :      * at runtime
     897             :      */
     898        1000 :     function->extra_warnings = 0;
     899        1000 :     function->extra_errors = 0;
     900             : 
     901        1000 :     function->nstatements = 0;
     902        1000 :     function->requires_procedure_resowner = false;
     903             : 
     904        1000 :     plpgsql_ns_init();
     905        1000 :     plpgsql_ns_push(func_name, PLPGSQL_LABEL_BLOCK);
     906        1000 :     plpgsql_DumpExecTree = false;
     907        1000 :     plpgsql_start_datums();
     908             : 
     909             :     /* Set up as though in a function returning VOID */
     910        1000 :     function->fn_rettype = VOIDOID;
     911        1000 :     function->fn_retset = false;
     912        1000 :     function->fn_retistuple = false;
     913        1000 :     function->fn_retisdomain = false;
     914        1000 :     function->fn_prokind = PROKIND_FUNCTION;
     915             :     /* a bit of hardwired knowledge about type VOID here */
     916        1000 :     function->fn_retbyval = true;
     917        1000 :     function->fn_rettyplen = sizeof(int32);
     918             : 
     919             :     /*
     920             :      * Remember if function is STABLE/IMMUTABLE.  XXX would it be better to
     921             :      * set this true inside a read-only transaction?  Not clear.
     922             :      */
     923        1000 :     function->fn_readonly = false;
     924             : 
     925             :     /*
     926             :      * Create the magic FOUND variable.
     927             :      */
     928        1000 :     var = plpgsql_build_variable("found", 0,
     929             :                                  plpgsql_build_datatype(BOOLOID,
     930             :                                                         -1,
     931             :                                                         InvalidOid,
     932             :                                                         NULL),
     933             :                                  true);
     934        1000 :     function->found_varno = var->dno;
     935             : 
     936             :     /*
     937             :      * Now parse the function's text
     938             :      */
     939        1000 :     parse_rc = plpgsql_yyparse();
     940         944 :     if (parse_rc != 0)
     941           0 :         elog(ERROR, "plpgsql parser returned %d", parse_rc);
     942         944 :     function->action = plpgsql_parse_result;
     943             : 
     944         944 :     plpgsql_scanner_finish();
     945             : 
     946             :     /*
     947             :      * If it returns VOID (always true at the moment), we allow control to
     948             :      * fall off the end without an explicit RETURN statement.
     949             :      */
     950         944 :     if (function->fn_rettype == VOIDOID)
     951         944 :         add_dummy_return(function);
     952             : 
     953             :     /*
     954             :      * Complete the function's info
     955             :      */
     956         944 :     function->fn_nargs = 0;
     957             : 
     958         944 :     plpgsql_finish_datums(function);
     959             : 
     960             :     /*
     961             :      * Pop the error context stack
     962             :      */
     963         944 :     error_context_stack = plerrcontext.previous;
     964         944 :     plpgsql_error_funcname = NULL;
     965             : 
     966         944 :     plpgsql_check_syntax = false;
     967             : 
     968         944 :     MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
     969         944 :     plpgsql_compile_tmp_cxt = NULL;
     970         944 :     return function;
     971             : }
     972             : 
     973             : 
     974             : /*
     975             :  * error context callback to let us supply a call-stack traceback.
     976             :  * If we are validating or executing an anonymous code block, the function
     977             :  * source text is passed as an argument.
     978             :  */
     979             : static void
     980         244 : plpgsql_compile_error_callback(void *arg)
     981             : {
     982         244 :     if (arg)
     983             :     {
     984             :         /*
     985             :          * Try to convert syntax error position to reference text of original
     986             :          * CREATE FUNCTION or DO command.
     987             :          */
     988         230 :         if (function_parse_error_transpose((const char *) arg))
     989         184 :             return;
     990             : 
     991             :         /*
     992             :          * Done if a syntax error position was reported; otherwise we have to
     993             :          * fall back to a "near line N" report.
     994             :          */
     995             :     }
     996             : 
     997          60 :     if (plpgsql_error_funcname)
     998          60 :         errcontext("compilation of PL/pgSQL function \"%s\" near line %d",
     999             :                    plpgsql_error_funcname, plpgsql_latest_lineno());
    1000             : }
    1001             : 
    1002             : 
    1003             : /*
    1004             :  * Add a name for a function parameter to the function's namespace
    1005             :  */
    1006             : static void
    1007        7624 : add_parameter_name(PLpgSQL_nsitem_type itemtype, int itemno, const char *name)
    1008             : {
    1009             :     /*
    1010             :      * Before adding the name, check for duplicates.  We need this even though
    1011             :      * functioncmds.c has a similar check, because that code explicitly
    1012             :      * doesn't complain about conflicting IN and OUT parameter names.  In
    1013             :      * plpgsql, such names are in the same namespace, so there is no way to
    1014             :      * disambiguate.
    1015             :      */
    1016        7624 :     if (plpgsql_ns_lookup(plpgsql_ns_top(), true,
    1017             :                           name, NULL, NULL,
    1018             :                           NULL) != NULL)
    1019           0 :         ereport(ERROR,
    1020             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
    1021             :                  errmsg("parameter name \"%s\" used more than once",
    1022             :                         name)));
    1023             : 
    1024             :     /* OK, add the name */
    1025        7624 :     plpgsql_ns_additem(itemtype, itemno, name);
    1026        7624 : }
    1027             : 
    1028             : /*
    1029             :  * Add a dummy RETURN statement to the given function's body
    1030             :  */
    1031             : static void
    1032        2894 : add_dummy_return(PLpgSQL_function *function)
    1033             : {
    1034             :     /*
    1035             :      * If the outer block has an EXCEPTION clause, we need to make a new outer
    1036             :      * block, since the added RETURN shouldn't act like it is inside the
    1037             :      * EXCEPTION clause.  Likewise, if it has a label, wrap it in a new outer
    1038             :      * block so that EXIT doesn't skip the RETURN.
    1039             :      */
    1040        2894 :     if (function->action->exceptions != NULL ||
    1041        2636 :         function->action->label != NULL)
    1042             :     {
    1043             :         PLpgSQL_stmt_block *new;
    1044             : 
    1045         284 :         new = palloc0(sizeof(PLpgSQL_stmt_block));
    1046         284 :         new->cmd_type = PLPGSQL_STMT_BLOCK;
    1047         284 :         new->stmtid = ++function->nstatements;
    1048         284 :         new->body = list_make1(function->action);
    1049             : 
    1050         284 :         function->action = new;
    1051             :     }
    1052        2894 :     if (function->action->body == NIL ||
    1053        2532 :         ((PLpgSQL_stmt *) llast(function->action->body))->cmd_type != PLPGSQL_STMT_RETURN)
    1054             :     {
    1055             :         PLpgSQL_stmt_return *new;
    1056             : 
    1057        2784 :         new = palloc0(sizeof(PLpgSQL_stmt_return));
    1058        2784 :         new->cmd_type = PLPGSQL_STMT_RETURN;
    1059        2784 :         new->stmtid = ++function->nstatements;
    1060        2784 :         new->expr = NULL;
    1061        2784 :         new->retvarno = function->out_param_varno;
    1062             : 
    1063        2784 :         function->action->body = lappend(function->action->body, new);
    1064             :     }
    1065        2894 : }
    1066             : 
    1067             : 
    1068             : /*
    1069             :  * plpgsql_parser_setup     set up parser hooks for dynamic parameters
    1070             :  *
    1071             :  * Note: this routine, and the hook functions it prepares for, are logically
    1072             :  * part of plpgsql parsing.  But they actually run during function execution,
    1073             :  * when we are ready to evaluate a SQL query or expression that has not
    1074             :  * previously been parsed and planned.
    1075             :  */
    1076             : void
    1077       29606 : plpgsql_parser_setup(struct ParseState *pstate, PLpgSQL_expr *expr)
    1078             : {
    1079       29606 :     pstate->p_pre_columnref_hook = plpgsql_pre_column_ref;
    1080       29606 :     pstate->p_post_columnref_hook = plpgsql_post_column_ref;
    1081       29606 :     pstate->p_paramref_hook = plpgsql_param_ref;
    1082             :     /* no need to use p_coerce_param_hook */
    1083       29606 :     pstate->p_ref_hook_state = (void *) expr;
    1084       29606 : }
    1085             : 
    1086             : /*
    1087             :  * plpgsql_pre_column_ref       parser callback before parsing a ColumnRef
    1088             :  */
    1089             : static Node *
    1090       34394 : plpgsql_pre_column_ref(ParseState *pstate, ColumnRef *cref)
    1091             : {
    1092       34394 :     PLpgSQL_expr *expr = (PLpgSQL_expr *) pstate->p_ref_hook_state;
    1093             : 
    1094       34394 :     if (expr->func->resolve_option == PLPGSQL_RESOLVE_VARIABLE)
    1095          12 :         return resolve_column_ref(pstate, expr, cref, false);
    1096             :     else
    1097       34382 :         return NULL;
    1098             : }
    1099             : 
    1100             : /*
    1101             :  * plpgsql_post_column_ref      parser callback after parsing a ColumnRef
    1102             :  */
    1103             : static Node *
    1104       34388 : plpgsql_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var)
    1105             : {
    1106       34388 :     PLpgSQL_expr *expr = (PLpgSQL_expr *) pstate->p_ref_hook_state;
    1107             :     Node       *myvar;
    1108             : 
    1109       34388 :     if (expr->func->resolve_option == PLPGSQL_RESOLVE_VARIABLE)
    1110           6 :         return NULL;            /* we already found there's no match */
    1111             : 
    1112       34382 :     if (expr->func->resolve_option == PLPGSQL_RESOLVE_COLUMN && var != NULL)
    1113          12 :         return NULL;            /* there's a table column, prefer that */
    1114             : 
    1115             :     /*
    1116             :      * If we find a record/row variable but can't match a field name, throw
    1117             :      * error if there was no core resolution for the ColumnRef either.  In
    1118             :      * that situation, the reference is inevitably going to fail, and
    1119             :      * complaining about the record/row variable is likely to be more on-point
    1120             :      * than the core parser's error message.  (It's too bad we don't have
    1121             :      * access to transformColumnRef's internal crerr state here, as in case of
    1122             :      * a conflict with a table name this could still be less than the most
    1123             :      * helpful error message possible.)
    1124             :      */
    1125       34370 :     myvar = resolve_column_ref(pstate, expr, cref, (var == NULL));
    1126             : 
    1127       34348 :     if (myvar != NULL && var != NULL)
    1128             :     {
    1129             :         /*
    1130             :          * We could leave it to the core parser to throw this error, but we
    1131             :          * can add a more useful detail message than the core could.
    1132             :          */
    1133           6 :         ereport(ERROR,
    1134             :                 (errcode(ERRCODE_AMBIGUOUS_COLUMN),
    1135             :                  errmsg("column reference \"%s\" is ambiguous",
    1136             :                         NameListToString(cref->fields)),
    1137             :                  errdetail("It could refer to either a PL/pgSQL variable or a table column."),
    1138             :                  parser_errposition(pstate, cref->location)));
    1139             :     }
    1140             : 
    1141       34342 :     return myvar;
    1142             : }
    1143             : 
    1144             : /*
    1145             :  * plpgsql_param_ref        parser callback for ParamRefs ($n symbols)
    1146             :  */
    1147             : static Node *
    1148         958 : plpgsql_param_ref(ParseState *pstate, ParamRef *pref)
    1149             : {
    1150         958 :     PLpgSQL_expr *expr = (PLpgSQL_expr *) pstate->p_ref_hook_state;
    1151             :     char        pname[32];
    1152             :     PLpgSQL_nsitem *nse;
    1153             : 
    1154         958 :     snprintf(pname, sizeof(pname), "$%d", pref->number);
    1155             : 
    1156         958 :     nse = plpgsql_ns_lookup(expr->ns, false,
    1157             :                             pname, NULL, NULL,
    1158             :                             NULL);
    1159             : 
    1160         958 :     if (nse == NULL)
    1161           0 :         return NULL;            /* name not known to plpgsql */
    1162             : 
    1163         958 :     return make_datum_param(expr, nse->itemno, pref->location);
    1164             : }
    1165             : 
    1166             : /*
    1167             :  * resolve_column_ref       attempt to resolve a ColumnRef as a plpgsql var
    1168             :  *
    1169             :  * Returns the translated node structure, or NULL if name not found
    1170             :  *
    1171             :  * error_if_no_field tells whether to throw error or quietly return NULL if
    1172             :  * we are able to match a record/row name but don't find a field name match.
    1173             :  */
    1174             : static Node *
    1175       34382 : resolve_column_ref(ParseState *pstate, PLpgSQL_expr *expr,
    1176             :                    ColumnRef *cref, bool error_if_no_field)
    1177             : {
    1178             :     PLpgSQL_execstate *estate;
    1179             :     PLpgSQL_nsitem *nse;
    1180             :     const char *name1;
    1181       34382 :     const char *name2 = NULL;
    1182       34382 :     const char *name3 = NULL;
    1183       34382 :     const char *colname = NULL;
    1184             :     int         nnames;
    1185       34382 :     int         nnames_scalar = 0;
    1186       34382 :     int         nnames_wholerow = 0;
    1187       34382 :     int         nnames_field = 0;
    1188             : 
    1189             :     /*
    1190             :      * We use the function's current estate to resolve parameter data types.
    1191             :      * This is really pretty bogus because there is no provision for updating
    1192             :      * plans when those types change ...
    1193             :      */
    1194       34382 :     estate = expr->func->cur_estate;
    1195             : 
    1196             :     /*----------
    1197             :      * The allowed syntaxes are:
    1198             :      *
    1199             :      * A        Scalar variable reference, or whole-row record reference.
    1200             :      * A.B      Qualified scalar or whole-row reference, or field reference.
    1201             :      * A.B.C    Qualified record field reference.
    1202             :      * A.*      Whole-row record reference.
    1203             :      * A.B.*    Qualified whole-row record reference.
    1204             :      *----------
    1205             :      */
    1206       34382 :     switch (list_length(cref->fields))
    1207             :     {
    1208       28784 :         case 1:
    1209             :             {
    1210       28784 :                 Node       *field1 = (Node *) linitial(cref->fields);
    1211             : 
    1212       28784 :                 name1 = strVal(field1);
    1213       28784 :                 nnames_scalar = 1;
    1214       28784 :                 nnames_wholerow = 1;
    1215       28784 :                 break;
    1216             :             }
    1217        5568 :         case 2:
    1218             :             {
    1219        5568 :                 Node       *field1 = (Node *) linitial(cref->fields);
    1220        5568 :                 Node       *field2 = (Node *) lsecond(cref->fields);
    1221             : 
    1222        5568 :                 name1 = strVal(field1);
    1223             : 
    1224             :                 /* Whole-row reference? */
    1225        5568 :                 if (IsA(field2, A_Star))
    1226             :                 {
    1227             :                     /* Set name2 to prevent matches to scalar variables */
    1228         100 :                     name2 = "*";
    1229         100 :                     nnames_wholerow = 1;
    1230         100 :                     break;
    1231             :                 }
    1232             : 
    1233        5468 :                 name2 = strVal(field2);
    1234        5468 :                 colname = name2;
    1235        5468 :                 nnames_scalar = 2;
    1236        5468 :                 nnames_wholerow = 2;
    1237        5468 :                 nnames_field = 1;
    1238        5468 :                 break;
    1239             :             }
    1240          30 :         case 3:
    1241             :             {
    1242          30 :                 Node       *field1 = (Node *) linitial(cref->fields);
    1243          30 :                 Node       *field2 = (Node *) lsecond(cref->fields);
    1244          30 :                 Node       *field3 = (Node *) lthird(cref->fields);
    1245             : 
    1246          30 :                 name1 = strVal(field1);
    1247          30 :                 name2 = strVal(field2);
    1248             : 
    1249             :                 /* Whole-row reference? */
    1250          30 :                 if (IsA(field3, A_Star))
    1251             :                 {
    1252             :                     /* Set name3 to prevent matches to scalar variables */
    1253           0 :                     name3 = "*";
    1254           0 :                     nnames_wholerow = 2;
    1255           0 :                     break;
    1256             :                 }
    1257             : 
    1258          30 :                 name3 = strVal(field3);
    1259          30 :                 colname = name3;
    1260          30 :                 nnames_field = 2;
    1261          30 :                 break;
    1262             :             }
    1263           0 :         default:
    1264             :             /* too many names, ignore */
    1265           0 :             return NULL;
    1266             :     }
    1267             : 
    1268       34382 :     nse = plpgsql_ns_lookup(expr->ns, false,
    1269             :                             name1, name2, name3,
    1270             :                             &nnames);
    1271             : 
    1272       34382 :     if (nse == NULL)
    1273        3894 :         return NULL;            /* name not known to plpgsql */
    1274             : 
    1275       30488 :     switch (nse->itemtype)
    1276             :     {
    1277       23184 :         case PLPGSQL_NSTYPE_VAR:
    1278       23184 :             if (nnames == nnames_scalar)
    1279       23184 :                 return make_datum_param(expr, nse->itemno, cref->location);
    1280           0 :             break;
    1281        7304 :         case PLPGSQL_NSTYPE_REC:
    1282        7304 :             if (nnames == nnames_wholerow)
    1283        2316 :                 return make_datum_param(expr, nse->itemno, cref->location);
    1284        4988 :             if (nnames == nnames_field)
    1285             :             {
    1286             :                 /* colname could be a field in this record */
    1287        4988 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) estate->datums[nse->itemno];
    1288             :                 int         i;
    1289             : 
    1290             :                 /* search for a datum referencing this field */
    1291        4988 :                 i = rec->firstfield;
    1292       11218 :                 while (i >= 0)
    1293             :                 {
    1294       11218 :                     PLpgSQL_recfield *fld = (PLpgSQL_recfield *) estate->datums[i];
    1295             : 
    1296             :                     Assert(fld->dtype == PLPGSQL_DTYPE_RECFIELD &&
    1297             :                            fld->recparentno == nse->itemno);
    1298       11218 :                     if (strcmp(fld->fieldname, colname) == 0)
    1299             :                     {
    1300        4988 :                         return make_datum_param(expr, i, cref->location);
    1301             :                     }
    1302        6230 :                     i = fld->nextfield;
    1303             :                 }
    1304             : 
    1305             :                 /*
    1306             :                  * We should not get here, because a RECFIELD datum should
    1307             :                  * have been built at parse time for every possible qualified
    1308             :                  * reference to fields of this record.  But if we do, handle
    1309             :                  * it like field-not-found: throw error or return NULL.
    1310             :                  */
    1311           0 :                 if (error_if_no_field)
    1312           0 :                     ereport(ERROR,
    1313             :                             (errcode(ERRCODE_UNDEFINED_COLUMN),
    1314             :                              errmsg("record \"%s\" has no field \"%s\"",
    1315             :                                     (nnames_field == 1) ? name1 : name2,
    1316             :                                     colname),
    1317             :                              parser_errposition(pstate, cref->location)));
    1318             :             }
    1319           0 :             break;
    1320           0 :         default:
    1321           0 :             elog(ERROR, "unrecognized plpgsql itemtype: %d", nse->itemtype);
    1322             :     }
    1323             : 
    1324             :     /* Name format doesn't match the plpgsql variable type */
    1325           0 :     return NULL;
    1326             : }
    1327             : 
    1328             : /*
    1329             :  * Helper for columnref parsing: build a Param referencing a plpgsql datum,
    1330             :  * and make sure that that datum is listed in the expression's paramnos.
    1331             :  */
    1332             : static Node *
    1333       31446 : make_datum_param(PLpgSQL_expr *expr, int dno, int location)
    1334             : {
    1335             :     PLpgSQL_execstate *estate;
    1336             :     PLpgSQL_datum *datum;
    1337             :     Param      *param;
    1338             :     MemoryContext oldcontext;
    1339             : 
    1340             :     /* see comment in resolve_column_ref */
    1341       31446 :     estate = expr->func->cur_estate;
    1342             :     Assert(dno >= 0 && dno < estate->ndatums);
    1343       31446 :     datum = estate->datums[dno];
    1344             : 
    1345             :     /*
    1346             :      * Bitmapset must be allocated in function's permanent memory context
    1347             :      */
    1348       31446 :     oldcontext = MemoryContextSwitchTo(expr->func->fn_cxt);
    1349       31446 :     expr->paramnos = bms_add_member(expr->paramnos, dno);
    1350       31446 :     MemoryContextSwitchTo(oldcontext);
    1351             : 
    1352       31446 :     param = makeNode(Param);
    1353       31446 :     param->paramkind = PARAM_EXTERN;
    1354       31446 :     param->paramid = dno + 1;
    1355       31446 :     plpgsql_exec_get_datum_type_info(estate,
    1356             :                                      datum,
    1357             :                                      &param->paramtype,
    1358             :                                      &param->paramtypmod,
    1359             :                                      &param->paramcollid);
    1360       31424 :     param->location = location;
    1361             : 
    1362       31424 :     return (Node *) param;
    1363             : }
    1364             : 
    1365             : 
    1366             : /* ----------
    1367             :  * plpgsql_parse_word       The scanner calls this to postparse
    1368             :  *              any single word that is not a reserved keyword.
    1369             :  *
    1370             :  * word1 is the downcased/dequoted identifier; it must be palloc'd in the
    1371             :  * function's long-term memory context.
    1372             :  *
    1373             :  * yytxt is the original token text; we need this to check for quoting,
    1374             :  * so that later checks for unreserved keywords work properly.
    1375             :  *
    1376             :  * We attempt to recognize the token as a variable only if lookup is true
    1377             :  * and the plpgsql_IdentifierLookup context permits it.
    1378             :  *
    1379             :  * If recognized as a variable, fill in *wdatum and return true;
    1380             :  * if not recognized, fill in *word and return false.
    1381             :  * (Note: those two pointers actually point to members of the same union,
    1382             :  * but for notational reasons we pass them separately.)
    1383             :  * ----------
    1384             :  */
    1385             : bool
    1386      114418 : plpgsql_parse_word(char *word1, const char *yytxt, bool lookup,
    1387             :                    PLwdatum *wdatum, PLword *word)
    1388             : {
    1389             :     PLpgSQL_nsitem *ns;
    1390             : 
    1391             :     /*
    1392             :      * We should not lookup variables in DECLARE sections.  In SQL
    1393             :      * expressions, there's no need to do so either --- lookup will happen
    1394             :      * when the expression is compiled.
    1395             :      */
    1396      114418 :     if (lookup && plpgsql_IdentifierLookup == IDENTIFIER_LOOKUP_NORMAL)
    1397             :     {
    1398             :         /*
    1399             :          * Do a lookup in the current namespace stack
    1400             :          */
    1401       25820 :         ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
    1402             :                                word1, NULL, NULL,
    1403             :                                NULL);
    1404             : 
    1405       25820 :         if (ns != NULL)
    1406             :         {
    1407       14972 :             switch (ns->itemtype)
    1408             :             {
    1409       14972 :                 case PLPGSQL_NSTYPE_VAR:
    1410             :                 case PLPGSQL_NSTYPE_REC:
    1411       14972 :                     wdatum->datum = plpgsql_Datums[ns->itemno];
    1412       14972 :                     wdatum->ident = word1;
    1413       14972 :                     wdatum->quoted = (yytxt[0] == '"');
    1414       14972 :                     wdatum->idents = NIL;
    1415       14972 :                     return true;
    1416             : 
    1417           0 :                 default:
    1418             :                     /* plpgsql_ns_lookup should never return anything else */
    1419           0 :                     elog(ERROR, "unrecognized plpgsql itemtype: %d",
    1420             :                          ns->itemtype);
    1421             :             }
    1422             :         }
    1423             :     }
    1424             : 
    1425             :     /*
    1426             :      * Nothing found - up to now it's a word without any special meaning for
    1427             :      * us.
    1428             :      */
    1429       99446 :     word->ident = word1;
    1430       99446 :     word->quoted = (yytxt[0] == '"');
    1431       99446 :     return false;
    1432             : }
    1433             : 
    1434             : 
    1435             : /* ----------
    1436             :  * plpgsql_parse_dblword        Same lookup for two words
    1437             :  *                  separated by a dot.
    1438             :  * ----------
    1439             :  */
    1440             : bool
    1441        8016 : plpgsql_parse_dblword(char *word1, char *word2,
    1442             :                       PLwdatum *wdatum, PLcword *cword)
    1443             : {
    1444             :     PLpgSQL_nsitem *ns;
    1445             :     List       *idents;
    1446             :     int         nnames;
    1447             : 
    1448        8016 :     idents = list_make2(makeString(word1),
    1449             :                         makeString(word2));
    1450             : 
    1451             :     /*
    1452             :      * We should do nothing in DECLARE sections.  In SQL expressions, we
    1453             :      * really only need to make sure that RECFIELD datums are created when
    1454             :      * needed.  In all the cases handled by this function, returning a T_DATUM
    1455             :      * with a two-word idents string is the right thing.
    1456             :      */
    1457        8016 :     if (plpgsql_IdentifierLookup != IDENTIFIER_LOOKUP_DECLARE)
    1458             :     {
    1459             :         /*
    1460             :          * Do a lookup in the current namespace stack
    1461             :          */
    1462        7958 :         ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
    1463             :                                word1, word2, NULL,
    1464             :                                &nnames);
    1465        7958 :         if (ns != NULL)
    1466             :         {
    1467        7036 :             switch (ns->itemtype)
    1468             :             {
    1469          24 :                 case PLPGSQL_NSTYPE_VAR:
    1470             :                     /* Block-qualified reference to scalar variable. */
    1471          24 :                     wdatum->datum = plpgsql_Datums[ns->itemno];
    1472          24 :                     wdatum->ident = NULL;
    1473          24 :                     wdatum->quoted = false; /* not used */
    1474          24 :                     wdatum->idents = idents;
    1475          24 :                     return true;
    1476             : 
    1477        7012 :                 case PLPGSQL_NSTYPE_REC:
    1478        7012 :                     if (nnames == 1)
    1479             :                     {
    1480             :                         /*
    1481             :                          * First word is a record name, so second word could
    1482             :                          * be a field in this record.  We build a RECFIELD
    1483             :                          * datum whether it is or not --- any error will be
    1484             :                          * detected later.
    1485             :                          */
    1486             :                         PLpgSQL_rec *rec;
    1487             :                         PLpgSQL_recfield *new;
    1488             : 
    1489        6996 :                         rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]);
    1490        6996 :                         new = plpgsql_build_recfield(rec, word2);
    1491             : 
    1492        6996 :                         wdatum->datum = (PLpgSQL_datum *) new;
    1493             :                     }
    1494             :                     else
    1495             :                     {
    1496             :                         /* Block-qualified reference to record variable. */
    1497          16 :                         wdatum->datum = plpgsql_Datums[ns->itemno];
    1498             :                     }
    1499        7012 :                     wdatum->ident = NULL;
    1500        7012 :                     wdatum->quoted = false; /* not used */
    1501        7012 :                     wdatum->idents = idents;
    1502        7012 :                     return true;
    1503             : 
    1504           0 :                 default:
    1505           0 :                     break;
    1506             :             }
    1507         980 :         }
    1508             :     }
    1509             : 
    1510             :     /* Nothing found */
    1511         980 :     cword->idents = idents;
    1512         980 :     return false;
    1513             : }
    1514             : 
    1515             : 
    1516             : /* ----------
    1517             :  * plpgsql_parse_tripword       Same lookup for three words
    1518             :  *                  separated by dots.
    1519             :  * ----------
    1520             :  */
    1521             : bool
    1522          60 : plpgsql_parse_tripword(char *word1, char *word2, char *word3,
    1523             :                        PLwdatum *wdatum, PLcword *cword)
    1524             : {
    1525             :     PLpgSQL_nsitem *ns;
    1526             :     List       *idents;
    1527             :     int         nnames;
    1528             : 
    1529             :     /*
    1530             :      * We should do nothing in DECLARE sections.  In SQL expressions, we need
    1531             :      * to make sure that RECFIELD datums are created when needed, and we need
    1532             :      * to be careful about how many names are reported as belonging to the
    1533             :      * T_DATUM: the third word could be a sub-field reference, which we don't
    1534             :      * care about here.
    1535             :      */
    1536          60 :     if (plpgsql_IdentifierLookup != IDENTIFIER_LOOKUP_DECLARE)
    1537             :     {
    1538             :         /*
    1539             :          * Do a lookup in the current namespace stack.  Must find a record
    1540             :          * reference, else ignore.
    1541             :          */
    1542          46 :         ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
    1543             :                                word1, word2, word3,
    1544             :                                &nnames);
    1545          46 :         if (ns != NULL)
    1546             :         {
    1547          42 :             switch (ns->itemtype)
    1548             :             {
    1549          42 :                 case PLPGSQL_NSTYPE_REC:
    1550             :                     {
    1551             :                         PLpgSQL_rec *rec;
    1552             :                         PLpgSQL_recfield *new;
    1553             : 
    1554          42 :                         rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]);
    1555          42 :                         if (nnames == 1)
    1556             :                         {
    1557             :                             /*
    1558             :                              * First word is a record name, so second word
    1559             :                              * could be a field in this record (and the third,
    1560             :                              * a sub-field).  We build a RECFIELD datum
    1561             :                              * whether it is or not --- any error will be
    1562             :                              * detected later.
    1563             :                              */
    1564           6 :                             new = plpgsql_build_recfield(rec, word2);
    1565           6 :                             idents = list_make2(makeString(word1),
    1566             :                                                 makeString(word2));
    1567             :                         }
    1568             :                         else
    1569             :                         {
    1570             :                             /* Block-qualified reference to record variable. */
    1571          36 :                             new = plpgsql_build_recfield(rec, word3);
    1572          36 :                             idents = list_make3(makeString(word1),
    1573             :                                                 makeString(word2),
    1574             :                                                 makeString(word3));
    1575             :                         }
    1576          42 :                         wdatum->datum = (PLpgSQL_datum *) new;
    1577          42 :                         wdatum->ident = NULL;
    1578          42 :                         wdatum->quoted = false; /* not used */
    1579          42 :                         wdatum->idents = idents;
    1580          42 :                         return true;
    1581             :                     }
    1582             : 
    1583           0 :                 default:
    1584           0 :                     break;
    1585             :             }
    1586          18 :         }
    1587             :     }
    1588             : 
    1589             :     /* Nothing found */
    1590          18 :     idents = list_make3(makeString(word1),
    1591             :                         makeString(word2),
    1592             :                         makeString(word3));
    1593          18 :     cword->idents = idents;
    1594          18 :     return false;
    1595             : }
    1596             : 
    1597             : 
    1598             : /* ----------
    1599             :  * plpgsql_parse_wordtype   The scanner found word%TYPE. word should be
    1600             :  *              a pre-existing variable name.
    1601             :  *
    1602             :  * Returns datatype struct.  Throws error if no match found for word.
    1603             :  * ----------
    1604             :  */
    1605             : PLpgSQL_type *
    1606          48 : plpgsql_parse_wordtype(char *ident)
    1607             : {
    1608             :     PLpgSQL_nsitem *nse;
    1609             : 
    1610             :     /*
    1611             :      * Do a lookup in the current namespace stack
    1612             :      */
    1613          48 :     nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
    1614             :                             ident, NULL, NULL,
    1615             :                             NULL);
    1616             : 
    1617          48 :     if (nse != NULL)
    1618             :     {
    1619          44 :         switch (nse->itemtype)
    1620             :         {
    1621          38 :             case PLPGSQL_NSTYPE_VAR:
    1622          38 :                 return ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
    1623           6 :             case PLPGSQL_NSTYPE_REC:
    1624           6 :                 return ((PLpgSQL_rec *) (plpgsql_Datums[nse->itemno]))->datatype;
    1625           0 :             default:
    1626           0 :                 break;
    1627             :         }
    1628           4 :     }
    1629             : 
    1630             :     /* No match, complain */
    1631           4 :     ereport(ERROR,
    1632             :             (errcode(ERRCODE_UNDEFINED_OBJECT),
    1633             :              errmsg("variable \"%s\" does not exist", ident)));
    1634             :     return NULL;                /* keep compiler quiet */
    1635             : }
    1636             : 
    1637             : 
    1638             : /* ----------
    1639             :  * plpgsql_parse_cwordtype      Same lookup for compositeword%TYPE
    1640             :  *
    1641             :  * Here, we allow either a block-qualified variable name, or a reference
    1642             :  * to a column of some table.  (If we must throw error, we assume that the
    1643             :  * latter case was intended.)
    1644             :  * ----------
    1645             :  */
    1646             : PLpgSQL_type *
    1647          36 : plpgsql_parse_cwordtype(List *idents)
    1648             : {
    1649          36 :     PLpgSQL_type *dtype = NULL;
    1650             :     PLpgSQL_nsitem *nse;
    1651             :     int         nnames;
    1652          36 :     RangeVar   *relvar = NULL;
    1653          36 :     const char *fldname = NULL;
    1654             :     Oid         classOid;
    1655          36 :     HeapTuple   attrtup = NULL;
    1656          36 :     HeapTuple   typetup = NULL;
    1657             :     Form_pg_attribute attrStruct;
    1658             :     MemoryContext oldCxt;
    1659             : 
    1660             :     /* Avoid memory leaks in the long-term function context */
    1661          36 :     oldCxt = MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
    1662             : 
    1663          36 :     if (list_length(idents) == 2)
    1664             :     {
    1665             :         /*
    1666             :          * Do a lookup in the current namespace stack
    1667             :          */
    1668          24 :         nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
    1669          24 :                                 strVal(linitial(idents)),
    1670          24 :                                 strVal(lsecond(idents)),
    1671             :                                 NULL,
    1672             :                                 &nnames);
    1673             : 
    1674          24 :         if (nse != NULL && nse->itemtype == PLPGSQL_NSTYPE_VAR)
    1675             :         {
    1676             :             /* Block-qualified reference to scalar variable. */
    1677           2 :             dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
    1678           2 :             goto done;
    1679             :         }
    1680          22 :         else if (nse != NULL && nse->itemtype == PLPGSQL_NSTYPE_REC &&
    1681           2 :                  nnames == 2)
    1682             :         {
    1683             :             /* Block-qualified reference to record variable. */
    1684           2 :             dtype = ((PLpgSQL_rec *) (plpgsql_Datums[nse->itemno]))->datatype;
    1685           2 :             goto done;
    1686             :         }
    1687             : 
    1688             :         /*
    1689             :          * First word could also be a table name
    1690             :          */
    1691          20 :         relvar = makeRangeVar(NULL,
    1692          20 :                               strVal(linitial(idents)),
    1693             :                               -1);
    1694          20 :         fldname = strVal(lsecond(idents));
    1695             :     }
    1696             :     else
    1697             :     {
    1698             :         /*
    1699             :          * We could check for a block-qualified reference to a field of a
    1700             :          * record variable, but %TYPE is documented as applying to variables,
    1701             :          * not fields of variables.  Things would get rather ambiguous if we
    1702             :          * allowed either interpretation.
    1703             :          */
    1704             :         List       *rvnames;
    1705             : 
    1706             :         Assert(list_length(idents) > 2);
    1707          12 :         rvnames = list_delete_last(list_copy(idents));
    1708          12 :         relvar = makeRangeVarFromNameList(rvnames);
    1709          12 :         fldname = strVal(llast(idents));
    1710             :     }
    1711             : 
    1712             :     /* Look up relation name.  Can't lock it - we might not have privileges. */
    1713          32 :     classOid = RangeVarGetRelid(relvar, NoLock, false);
    1714             : 
    1715             :     /*
    1716             :      * Fetch the named table field and its type
    1717             :      */
    1718          26 :     attrtup = SearchSysCacheAttName(classOid, fldname);
    1719          26 :     if (!HeapTupleIsValid(attrtup))
    1720           2 :         ereport(ERROR,
    1721             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    1722             :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
    1723             :                         fldname, relvar->relname)));
    1724          24 :     attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
    1725             : 
    1726          24 :     typetup = SearchSysCache1(TYPEOID,
    1727             :                               ObjectIdGetDatum(attrStruct->atttypid));
    1728          24 :     if (!HeapTupleIsValid(typetup))
    1729           0 :         elog(ERROR, "cache lookup failed for type %u", attrStruct->atttypid);
    1730             : 
    1731             :     /*
    1732             :      * Found that - build a compiler type struct in the caller's cxt and
    1733             :      * return it.  Note that we treat the type as being found-by-OID; no
    1734             :      * attempt to re-look-up the type name will happen during invalidations.
    1735             :      */
    1736          24 :     MemoryContextSwitchTo(oldCxt);
    1737          24 :     dtype = build_datatype(typetup,
    1738             :                            attrStruct->atttypmod,
    1739             :                            attrStruct->attcollation,
    1740             :                            NULL);
    1741          24 :     MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
    1742             : 
    1743          28 : done:
    1744          28 :     if (HeapTupleIsValid(attrtup))
    1745          24 :         ReleaseSysCache(attrtup);
    1746          28 :     if (HeapTupleIsValid(typetup))
    1747          24 :         ReleaseSysCache(typetup);
    1748             : 
    1749          28 :     MemoryContextSwitchTo(oldCxt);
    1750          28 :     return dtype;
    1751             : }
    1752             : 
    1753             : /* ----------
    1754             :  * plpgsql_parse_wordrowtype        Scanner found word%ROWTYPE.
    1755             :  *                  So word must be a table name.
    1756             :  * ----------
    1757             :  */
    1758             : PLpgSQL_type *
    1759          60 : plpgsql_parse_wordrowtype(char *ident)
    1760             : {
    1761             :     Oid         classOid;
    1762             :     Oid         typOid;
    1763             : 
    1764             :     /*
    1765             :      * Look up the relation.  Note that because relation rowtypes have the
    1766             :      * same names as their relations, this could be handled as a type lookup
    1767             :      * equally well; we use the relation lookup code path only because the
    1768             :      * errors thrown here have traditionally referred to relations not types.
    1769             :      * But we'll make a TypeName in case we have to do re-look-up of the type.
    1770             :      */
    1771          60 :     classOid = RelnameGetRelid(ident);
    1772          60 :     if (!OidIsValid(classOid))
    1773           4 :         ereport(ERROR,
    1774             :                 (errcode(ERRCODE_UNDEFINED_TABLE),
    1775             :                  errmsg("relation \"%s\" does not exist", ident)));
    1776             : 
    1777             :     /* Some relkinds lack type OIDs */
    1778          56 :     typOid = get_rel_type_id(classOid);
    1779          56 :     if (!OidIsValid(typOid))
    1780           0 :         ereport(ERROR,
    1781             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1782             :                  errmsg("relation \"%s\" does not have a composite type",
    1783             :                         ident)));
    1784             : 
    1785             :     /* Build and return the row type struct */
    1786          56 :     return plpgsql_build_datatype(typOid, -1, InvalidOid,
    1787             :                                   makeTypeName(ident));
    1788             : }
    1789             : 
    1790             : /* ----------
    1791             :  * plpgsql_parse_cwordrowtype       Scanner found compositeword%ROWTYPE.
    1792             :  *          So word must be a namespace qualified table name.
    1793             :  * ----------
    1794             :  */
    1795             : PLpgSQL_type *
    1796          16 : plpgsql_parse_cwordrowtype(List *idents)
    1797             : {
    1798             :     Oid         classOid;
    1799             :     Oid         typOid;
    1800             :     RangeVar   *relvar;
    1801             :     MemoryContext oldCxt;
    1802             : 
    1803             :     /*
    1804             :      * As above, this is a relation lookup but could be a type lookup if we
    1805             :      * weren't being backwards-compatible about error wording.
    1806             :      */
    1807             : 
    1808             :     /* Avoid memory leaks in long-term function context */
    1809          16 :     oldCxt = MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
    1810             : 
    1811             :     /* Look up relation name.  Can't lock it - we might not have privileges. */
    1812          16 :     relvar = makeRangeVarFromNameList(idents);
    1813          16 :     classOid = RangeVarGetRelid(relvar, NoLock, false);
    1814             : 
    1815             :     /* Some relkinds lack type OIDs */
    1816          10 :     typOid = get_rel_type_id(classOid);
    1817          10 :     if (!OidIsValid(typOid))
    1818           0 :         ereport(ERROR,
    1819             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    1820             :                  errmsg("relation \"%s\" does not have a composite type",
    1821             :                         relvar->relname)));
    1822             : 
    1823          10 :     MemoryContextSwitchTo(oldCxt);
    1824             : 
    1825             :     /* Build and return the row type struct */
    1826          10 :     return plpgsql_build_datatype(typOid, -1, InvalidOid,
    1827             :                                   makeTypeNameFromNameList(idents));
    1828             : }
    1829             : 
    1830             : /*
    1831             :  * plpgsql_build_variable - build a datum-array entry of a given
    1832             :  * datatype
    1833             :  *
    1834             :  * The returned struct may be a PLpgSQL_var or PLpgSQL_rec
    1835             :  * depending on the given datatype, and is allocated via
    1836             :  * palloc.  The struct is automatically added to the current datum
    1837             :  * array, and optionally to the current namespace.
    1838             :  */
    1839             : PLpgSQL_variable *
    1840       56736 : plpgsql_build_variable(const char *refname, int lineno, PLpgSQL_type *dtype,
    1841             :                        bool add2namespace)
    1842             : {
    1843             :     PLpgSQL_variable *result;
    1844             : 
    1845       56736 :     switch (dtype->ttype)
    1846             :     {
    1847       55290 :         case PLPGSQL_TTYPE_SCALAR:
    1848             :             {
    1849             :                 /* Ordinary scalar datatype */
    1850             :                 PLpgSQL_var *var;
    1851             : 
    1852       55290 :                 var = palloc0(sizeof(PLpgSQL_var));
    1853       55290 :                 var->dtype = PLPGSQL_DTYPE_VAR;
    1854       55290 :                 var->refname = pstrdup(refname);
    1855       55290 :                 var->lineno = lineno;
    1856       55290 :                 var->datatype = dtype;
    1857             :                 /* other fields are left as 0, might be changed by caller */
    1858             : 
    1859             :                 /* preset to NULL */
    1860       55290 :                 var->value = 0;
    1861       55290 :                 var->isnull = true;
    1862       55290 :                 var->freeval = false;
    1863             : 
    1864       55290 :                 plpgsql_adddatum((PLpgSQL_datum *) var);
    1865       55290 :                 if (add2namespace)
    1866       50984 :                     plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR,
    1867             :                                        var->dno,
    1868             :                                        refname);
    1869       55290 :                 result = (PLpgSQL_variable *) var;
    1870       55290 :                 break;
    1871             :             }
    1872        1442 :         case PLPGSQL_TTYPE_REC:
    1873             :             {
    1874             :                 /* Composite type -- build a record variable */
    1875             :                 PLpgSQL_rec *rec;
    1876             : 
    1877        1442 :                 rec = plpgsql_build_record(refname, lineno,
    1878             :                                            dtype, dtype->typoid,
    1879             :                                            add2namespace);
    1880        1442 :                 result = (PLpgSQL_variable *) rec;
    1881        1442 :                 break;
    1882             :             }
    1883           4 :         case PLPGSQL_TTYPE_PSEUDO:
    1884           4 :             ereport(ERROR,
    1885             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    1886             :                      errmsg("variable \"%s\" has pseudo-type %s",
    1887             :                             refname, format_type_be(dtype->typoid))));
    1888             :             result = NULL;      /* keep compiler quiet */
    1889             :             break;
    1890           0 :         default:
    1891           0 :             elog(ERROR, "unrecognized ttype: %d", dtype->ttype);
    1892             :             result = NULL;      /* keep compiler quiet */
    1893             :             break;
    1894             :     }
    1895             : 
    1896       56732 :     return result;
    1897             : }
    1898             : 
    1899             : /*
    1900             :  * Build empty named record variable, and optionally add it to namespace
    1901             :  */
    1902             : PLpgSQL_rec *
    1903        8644 : plpgsql_build_record(const char *refname, int lineno,
    1904             :                      PLpgSQL_type *dtype, Oid rectypeid,
    1905             :                      bool add2namespace)
    1906             : {
    1907             :     PLpgSQL_rec *rec;
    1908             : 
    1909        8644 :     rec = palloc0(sizeof(PLpgSQL_rec));
    1910        8644 :     rec->dtype = PLPGSQL_DTYPE_REC;
    1911        8644 :     rec->refname = pstrdup(refname);
    1912        8644 :     rec->lineno = lineno;
    1913             :     /* other fields are left as 0, might be changed by caller */
    1914        8644 :     rec->datatype = dtype;
    1915        8644 :     rec->rectypeid = rectypeid;
    1916        8644 :     rec->firstfield = -1;
    1917        8644 :     rec->erh = NULL;
    1918        8644 :     plpgsql_adddatum((PLpgSQL_datum *) rec);
    1919        8644 :     if (add2namespace)
    1920        8592 :         plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->dno, rec->refname);
    1921             : 
    1922        8644 :     return rec;
    1923             : }
    1924             : 
    1925             : /*
    1926             :  * Build a row-variable data structure given the component variables.
    1927             :  * Include a rowtupdesc, since we will need to materialize the row result.
    1928             :  */
    1929             : static PLpgSQL_row *
    1930         182 : build_row_from_vars(PLpgSQL_variable **vars, int numvars)
    1931             : {
    1932             :     PLpgSQL_row *row;
    1933             :     int         i;
    1934             : 
    1935         182 :     row = palloc0(sizeof(PLpgSQL_row));
    1936         182 :     row->dtype = PLPGSQL_DTYPE_ROW;
    1937         182 :     row->refname = "(unnamed row)";
    1938         182 :     row->lineno = -1;
    1939         182 :     row->rowtupdesc = CreateTemplateTupleDesc(numvars);
    1940         182 :     row->nfields = numvars;
    1941         182 :     row->fieldnames = palloc(numvars * sizeof(char *));
    1942         182 :     row->varnos = palloc(numvars * sizeof(int));
    1943             : 
    1944         586 :     for (i = 0; i < numvars; i++)
    1945             :     {
    1946         404 :         PLpgSQL_variable *var = vars[i];
    1947             :         Oid         typoid;
    1948             :         int32       typmod;
    1949             :         Oid         typcoll;
    1950             : 
    1951             :         /* Member vars of a row should never be const */
    1952             :         Assert(!var->isconst);
    1953             : 
    1954         404 :         switch (var->dtype)
    1955             :         {
    1956         404 :             case PLPGSQL_DTYPE_VAR:
    1957             :             case PLPGSQL_DTYPE_PROMISE:
    1958         404 :                 typoid = ((PLpgSQL_var *) var)->datatype->typoid;
    1959         404 :                 typmod = ((PLpgSQL_var *) var)->datatype->atttypmod;
    1960         404 :                 typcoll = ((PLpgSQL_var *) var)->datatype->collation;
    1961         404 :                 break;
    1962             : 
    1963           0 :             case PLPGSQL_DTYPE_REC:
    1964             :                 /* shouldn't need to revalidate rectypeid already... */
    1965           0 :                 typoid = ((PLpgSQL_rec *) var)->rectypeid;
    1966           0 :                 typmod = -1;    /* don't know typmod, if it's used at all */
    1967           0 :                 typcoll = InvalidOid;   /* composite types have no collation */
    1968           0 :                 break;
    1969             : 
    1970           0 :             default:
    1971           0 :                 elog(ERROR, "unrecognized dtype: %d", var->dtype);
    1972             :                 typoid = InvalidOid;    /* keep compiler quiet */
    1973             :                 typmod = 0;
    1974             :                 typcoll = InvalidOid;
    1975             :                 break;
    1976             :         }
    1977             : 
    1978         404 :         row->fieldnames[i] = var->refname;
    1979         404 :         row->varnos[i] = var->dno;
    1980             : 
    1981         404 :         TupleDescInitEntry(row->rowtupdesc, i + 1,
    1982         404 :                            var->refname,
    1983             :                            typoid, typmod,
    1984             :                            0);
    1985         404 :         TupleDescInitEntryCollation(row->rowtupdesc, i + 1, typcoll);
    1986             :     }
    1987             : 
    1988         182 :     return row;
    1989             : }
    1990             : 
    1991             : /*
    1992             :  * Build a RECFIELD datum for the named field of the specified record variable
    1993             :  *
    1994             :  * If there's already such a datum, just return it; we don't need duplicates.
    1995             :  */
    1996             : PLpgSQL_recfield *
    1997        7038 : plpgsql_build_recfield(PLpgSQL_rec *rec, const char *fldname)
    1998             : {
    1999             :     PLpgSQL_recfield *recfield;
    2000             :     int         i;
    2001             : 
    2002             :     /* search for an existing datum referencing this field */
    2003        7038 :     i = rec->firstfield;
    2004       10896 :     while (i >= 0)
    2005             :     {
    2006        6876 :         PLpgSQL_recfield *fld = (PLpgSQL_recfield *) plpgsql_Datums[i];
    2007             : 
    2008             :         Assert(fld->dtype == PLPGSQL_DTYPE_RECFIELD &&
    2009             :                fld->recparentno == rec->dno);
    2010        6876 :         if (strcmp(fld->fieldname, fldname) == 0)
    2011        3018 :             return fld;
    2012        3858 :         i = fld->nextfield;
    2013             :     }
    2014             : 
    2015             :     /* nope, so make a new one */
    2016        4020 :     recfield = palloc0(sizeof(PLpgSQL_recfield));
    2017        4020 :     recfield->dtype = PLPGSQL_DTYPE_RECFIELD;
    2018        4020 :     recfield->fieldname = pstrdup(fldname);
    2019        4020 :     recfield->recparentno = rec->dno;
    2020        4020 :     recfield->rectupledescid = INVALID_TUPLEDESC_IDENTIFIER;
    2021             : 
    2022        4020 :     plpgsql_adddatum((PLpgSQL_datum *) recfield);
    2023             : 
    2024             :     /* now we can link it into the parent's chain */
    2025        4020 :     recfield->nextfield = rec->firstfield;
    2026        4020 :     rec->firstfield = recfield->dno;
    2027             : 
    2028        4020 :     return recfield;
    2029             : }
    2030             : 
    2031             : /*
    2032             :  * plpgsql_build_datatype
    2033             :  *      Build PLpgSQL_type struct given type OID, typmod, collation,
    2034             :  *      and type's parsed name.
    2035             :  *
    2036             :  * If collation is not InvalidOid then it overrides the type's default
    2037             :  * collation.  But collation is ignored if the datatype is non-collatable.
    2038             :  *
    2039             :  * origtypname is the parsed form of what the user wrote as the type name.
    2040             :  * It can be NULL if the type could not be a composite type, or if it was
    2041             :  * identified by OID to begin with (e.g., it's a function argument type).
    2042             :  */
    2043             : PLpgSQL_type *
    2044       56600 : plpgsql_build_datatype(Oid typeOid, int32 typmod,
    2045             :                        Oid collation, TypeName *origtypname)
    2046             : {
    2047             :     HeapTuple   typeTup;
    2048             :     PLpgSQL_type *typ;
    2049             : 
    2050       56600 :     typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
    2051       56600 :     if (!HeapTupleIsValid(typeTup))
    2052           0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
    2053             : 
    2054       56600 :     typ = build_datatype(typeTup, typmod, collation, origtypname);
    2055             : 
    2056       56600 :     ReleaseSysCache(typeTup);
    2057             : 
    2058       56600 :     return typ;
    2059             : }
    2060             : 
    2061             : /*
    2062             :  * Utility subroutine to make a PLpgSQL_type struct given a pg_type entry
    2063             :  * and additional details (see comments for plpgsql_build_datatype).
    2064             :  */
    2065             : static PLpgSQL_type *
    2066       56768 : build_datatype(HeapTuple typeTup, int32 typmod,
    2067             :                Oid collation, TypeName *origtypname)
    2068             : {
    2069       56768 :     Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
    2070             :     PLpgSQL_type *typ;
    2071             : 
    2072       56768 :     if (!typeStruct->typisdefined)
    2073           0 :         ereport(ERROR,
    2074             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2075             :                  errmsg("type \"%s\" is only a shell",
    2076             :                         NameStr(typeStruct->typname))));
    2077             : 
    2078       56768 :     typ = (PLpgSQL_type *) palloc(sizeof(PLpgSQL_type));
    2079             : 
    2080       56768 :     typ->typname = pstrdup(NameStr(typeStruct->typname));
    2081       56768 :     typ->typoid = typeStruct->oid;
    2082       56768 :     switch (typeStruct->typtype)
    2083             :     {
    2084       55180 :         case TYPTYPE_BASE:
    2085             :         case TYPTYPE_ENUM:
    2086             :         case TYPTYPE_RANGE:
    2087             :         case TYPTYPE_MULTIRANGE:
    2088       55180 :             typ->ttype = PLPGSQL_TTYPE_SCALAR;
    2089       55180 :             break;
    2090         244 :         case TYPTYPE_COMPOSITE:
    2091         244 :             typ->ttype = PLPGSQL_TTYPE_REC;
    2092         244 :             break;
    2093         174 :         case TYPTYPE_DOMAIN:
    2094         174 :             if (type_is_rowtype(typeStruct->typbasetype))
    2095          36 :                 typ->ttype = PLPGSQL_TTYPE_REC;
    2096             :             else
    2097         138 :                 typ->ttype = PLPGSQL_TTYPE_SCALAR;
    2098         174 :             break;
    2099        1170 :         case TYPTYPE_PSEUDO:
    2100        1170 :             if (typ->typoid == RECORDOID)
    2101        1160 :                 typ->ttype = PLPGSQL_TTYPE_REC;
    2102             :             else
    2103          10 :                 typ->ttype = PLPGSQL_TTYPE_PSEUDO;
    2104        1170 :             break;
    2105           0 :         default:
    2106           0 :             elog(ERROR, "unrecognized typtype: %d",
    2107             :                  (int) typeStruct->typtype);
    2108             :             break;
    2109             :     }
    2110       56768 :     typ->typlen = typeStruct->typlen;
    2111       56768 :     typ->typbyval = typeStruct->typbyval;
    2112       56768 :     typ->typtype = typeStruct->typtype;
    2113       56768 :     typ->collation = typeStruct->typcollation;
    2114       56768 :     if (OidIsValid(collation) && OidIsValid(typ->collation))
    2115        1404 :         typ->collation = collation;
    2116             :     /* Detect if type is true array, or domain thereof */
    2117             :     /* NB: this is only used to decide whether to apply expand_array */
    2118       56768 :     if (typeStruct->typtype == TYPTYPE_BASE)
    2119             :     {
    2120             :         /*
    2121             :          * This test should include what get_element_type() checks.  We also
    2122             :          * disallow non-toastable array types (i.e. oidvector and int2vector).
    2123             :          */
    2124       59290 :         typ->typisarray = (IsTrueArrayType(typeStruct) &&
    2125        4194 :                            typeStruct->typstorage != TYPSTORAGE_PLAIN);
    2126             :     }
    2127        1672 :     else if (typeStruct->typtype == TYPTYPE_DOMAIN)
    2128             :     {
    2129             :         /* we can short-circuit looking up base types if it's not varlena */
    2130         444 :         typ->typisarray = (typeStruct->typlen == -1 &&
    2131         270 :                            typeStruct->typstorage != TYPSTORAGE_PLAIN &&
    2132          96 :                            OidIsValid(get_base_element_type(typeStruct->typbasetype)));
    2133             :     }
    2134             :     else
    2135        1498 :         typ->typisarray = false;
    2136       56768 :     typ->atttypmod = typmod;
    2137             : 
    2138             :     /*
    2139             :      * If it's a named composite type (or domain over one), find the typcache
    2140             :      * entry and record the current tupdesc ID, so we can detect changes
    2141             :      * (including drops).  We don't currently support on-the-fly replacement
    2142             :      * of non-composite types, else we might want to do this for them too.
    2143             :      */
    2144       56768 :     if (typ->ttype == PLPGSQL_TTYPE_REC && typ->typoid != RECORDOID)
    2145         280 :     {
    2146             :         TypeCacheEntry *typentry;
    2147             : 
    2148         280 :         typentry = lookup_type_cache(typ->typoid,
    2149             :                                      TYPECACHE_TUPDESC |
    2150             :                                      TYPECACHE_DOMAIN_BASE_INFO);
    2151         280 :         if (typentry->typtype == TYPTYPE_DOMAIN)
    2152          36 :             typentry = lookup_type_cache(typentry->domainBaseType,
    2153             :                                          TYPECACHE_TUPDESC);
    2154         280 :         if (typentry->tupDesc == NULL)
    2155           0 :             ereport(ERROR,
    2156             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2157             :                      errmsg("type %s is not composite",
    2158             :                             format_type_be(typ->typoid))));
    2159             : 
    2160         280 :         typ->origtypname = origtypname;
    2161         280 :         typ->tcache = typentry;
    2162         280 :         typ->tupdesc_id = typentry->tupDesc_identifier;
    2163             :     }
    2164             :     else
    2165             :     {
    2166       56488 :         typ->origtypname = NULL;
    2167       56488 :         typ->tcache = NULL;
    2168       56488 :         typ->tupdesc_id = 0;
    2169             :     }
    2170             : 
    2171       56768 :     return typ;
    2172             : }
    2173             : 
    2174             : /*
    2175             :  * Build an array type for the element type specified as argument.
    2176             :  */
    2177             : PLpgSQL_type *
    2178          28 : plpgsql_build_datatype_arrayof(PLpgSQL_type *dtype)
    2179             : {
    2180             :     Oid         array_typeid;
    2181             : 
    2182             :     /*
    2183             :      * If it's already an array type, use it as-is: Postgres doesn't do nested
    2184             :      * arrays.
    2185             :      */
    2186          28 :     if (dtype->typisarray)
    2187           0 :         return dtype;
    2188             : 
    2189          28 :     array_typeid = get_array_type(dtype->typoid);
    2190          28 :     if (!OidIsValid(array_typeid))
    2191           2 :         ereport(ERROR,
    2192             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2193             :                  errmsg("could not find array type for data type %s",
    2194             :                         format_type_be(dtype->typoid))));
    2195             : 
    2196             :     /* Note we inherit typmod and collation, if any, from the element type */
    2197          26 :     return plpgsql_build_datatype(array_typeid, dtype->atttypmod,
    2198             :                                   dtype->collation, NULL);
    2199             : }
    2200             : 
    2201             : /*
    2202             :  *  plpgsql_recognize_err_condition
    2203             :  *      Check condition name and translate it to SQLSTATE.
    2204             :  *
    2205             :  * Note: there are some cases where the same condition name has multiple
    2206             :  * entries in the table.  We arbitrarily return the first match.
    2207             :  */
    2208             : int
    2209         736 : plpgsql_recognize_err_condition(const char *condname, bool allow_sqlstate)
    2210             : {
    2211             :     int         i;
    2212             : 
    2213         736 :     if (allow_sqlstate)
    2214             :     {
    2215         694 :         if (strlen(condname) == 5 &&
    2216          52 :             strspn(condname, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") == 5)
    2217          52 :             return MAKE_SQLSTATE(condname[0],
    2218             :                                  condname[1],
    2219             :                                  condname[2],
    2220             :                                  condname[3],
    2221             :                                  condname[4]);
    2222             :     }
    2223             : 
    2224       78042 :     for (i = 0; exception_label_map[i].label != NULL; i++)
    2225             :     {
    2226       78042 :         if (strcmp(condname, exception_label_map[i].label) == 0)
    2227         684 :             return exception_label_map[i].sqlerrstate;
    2228             :     }
    2229             : 
    2230           0 :     ereport(ERROR,
    2231             :             (errcode(ERRCODE_UNDEFINED_OBJECT),
    2232             :              errmsg("unrecognized exception condition \"%s\"",
    2233             :                     condname)));
    2234             :     return 0;                   /* keep compiler quiet */
    2235             : }
    2236             : 
    2237             : /*
    2238             :  * plpgsql_parse_err_condition
    2239             :  *      Generate PLpgSQL_condition entry(s) for an exception condition name
    2240             :  *
    2241             :  * This has to be able to return a list because there are some duplicate
    2242             :  * names in the table of error code names.
    2243             :  */
    2244             : PLpgSQL_condition *
    2245         440 : plpgsql_parse_err_condition(char *condname)
    2246             : {
    2247             :     int         i;
    2248             :     PLpgSQL_condition *new;
    2249             :     PLpgSQL_condition *prev;
    2250             : 
    2251             :     /*
    2252             :      * XXX Eventually we will want to look for user-defined exception names
    2253             :      * here.
    2254             :      */
    2255             : 
    2256             :     /*
    2257             :      * OTHERS is represented as code 0 (which would map to '00000', but we
    2258             :      * have no need to represent that as an exception condition).
    2259             :      */
    2260         440 :     if (strcmp(condname, "others") == 0)
    2261             :     {
    2262         154 :         new = palloc(sizeof(PLpgSQL_condition));
    2263         154 :         new->sqlerrstate = 0;
    2264         154 :         new->condname = condname;
    2265         154 :         new->next = NULL;
    2266         154 :         return new;
    2267             :     }
    2268             : 
    2269         286 :     prev = NULL;
    2270       71500 :     for (i = 0; exception_label_map[i].label != NULL; i++)
    2271             :     {
    2272       71214 :         if (strcmp(condname, exception_label_map[i].label) == 0)
    2273             :         {
    2274         292 :             new = palloc(sizeof(PLpgSQL_condition));
    2275         292 :             new->sqlerrstate = exception_label_map[i].sqlerrstate;
    2276         292 :             new->condname = condname;
    2277         292 :             new->next = prev;
    2278         292 :             prev = new;
    2279             :         }
    2280             :     }
    2281             : 
    2282         286 :     if (!prev)
    2283           0 :         ereport(ERROR,
    2284             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2285             :                  errmsg("unrecognized exception condition \"%s\"",
    2286             :                         condname)));
    2287             : 
    2288         286 :     return prev;
    2289             : }
    2290             : 
    2291             : /* ----------
    2292             :  * plpgsql_start_datums         Initialize datum list at compile startup.
    2293             :  * ----------
    2294             :  */
    2295             : static void
    2296        8668 : plpgsql_start_datums(void)
    2297             : {
    2298        8668 :     datums_alloc = 128;
    2299        8668 :     plpgsql_nDatums = 0;
    2300             :     /* This is short-lived, so needn't allocate in function's cxt */
    2301        8668 :     plpgsql_Datums = MemoryContextAlloc(plpgsql_compile_tmp_cxt,
    2302             :                                         sizeof(PLpgSQL_datum *) * datums_alloc);
    2303             :     /* datums_last tracks what's been seen by plpgsql_add_initdatums() */
    2304        8668 :     datums_last = 0;
    2305        8668 : }
    2306             : 
    2307             : /* ----------
    2308             :  * plpgsql_adddatum         Add a variable, record or row
    2309             :  *                  to the compiler's datum list.
    2310             :  * ----------
    2311             :  */
    2312             : void
    2313       69436 : plpgsql_adddatum(PLpgSQL_datum *newdatum)
    2314             : {
    2315       69436 :     if (plpgsql_nDatums == datums_alloc)
    2316             :     {
    2317           0 :         datums_alloc *= 2;
    2318           0 :         plpgsql_Datums = repalloc(plpgsql_Datums, sizeof(PLpgSQL_datum *) * datums_alloc);
    2319             :     }
    2320             : 
    2321       69436 :     newdatum->dno = plpgsql_nDatums;
    2322       69436 :     plpgsql_Datums[plpgsql_nDatums++] = newdatum;
    2323       69436 : }
    2324             : 
    2325             : /* ----------
    2326             :  * plpgsql_finish_datums    Copy completed datum info into function struct.
    2327             :  * ----------
    2328             :  */
    2329             : static void
    2330        8490 : plpgsql_finish_datums(PLpgSQL_function *function)
    2331             : {
    2332        8490 :     Size        copiable_size = 0;
    2333             :     int         i;
    2334             : 
    2335        8490 :     function->ndatums = plpgsql_nDatums;
    2336        8490 :     function->datums = palloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums);
    2337       77572 :     for (i = 0; i < plpgsql_nDatums; i++)
    2338             :     {
    2339       69082 :         function->datums[i] = plpgsql_Datums[i];
    2340             : 
    2341             :         /* This must agree with copy_plpgsql_datums on what is copiable */
    2342       69082 :         switch (function->datums[i]->dtype)
    2343             :         {
    2344       54990 :             case PLPGSQL_DTYPE_VAR:
    2345             :             case PLPGSQL_DTYPE_PROMISE:
    2346       54990 :                 copiable_size += MAXALIGN(sizeof(PLpgSQL_var));
    2347       54990 :                 break;
    2348        8618 :             case PLPGSQL_DTYPE_REC:
    2349        8618 :                 copiable_size += MAXALIGN(sizeof(PLpgSQL_rec));
    2350        8618 :                 break;
    2351        5474 :             default:
    2352        5474 :                 break;
    2353             :         }
    2354             :     }
    2355        8490 :     function->copiable_size = copiable_size;
    2356        8490 : }
    2357             : 
    2358             : 
    2359             : /* ----------
    2360             :  * plpgsql_add_initdatums       Make an array of the datum numbers of
    2361             :  *                  all the initializable datums created since the last call
    2362             :  *                  to this function.
    2363             :  *
    2364             :  * If varnos is NULL, we just forget any datum entries created since the
    2365             :  * last call.
    2366             :  *
    2367             :  * This is used around a DECLARE section to create a list of the datums
    2368             :  * that have to be initialized at block entry.  Note that datums can also
    2369             :  * be created elsewhere than DECLARE, eg by a FOR-loop, but it is then
    2370             :  * the responsibility of special-purpose code to initialize them.
    2371             :  * ----------
    2372             :  */
    2373             : int
    2374        6784 : plpgsql_add_initdatums(int **varnos)
    2375             : {
    2376             :     int         i;
    2377        6784 :     int         n = 0;
    2378             : 
    2379             :     /*
    2380             :      * The set of dtypes recognized here must match what exec_stmt_block()
    2381             :      * cares about (re)initializing at block entry.
    2382             :      */
    2383       28758 :     for (i = datums_last; i < plpgsql_nDatums; i++)
    2384             :     {
    2385       21974 :         switch (plpgsql_Datums[i]->dtype)
    2386             :         {
    2387       13368 :             case PLPGSQL_DTYPE_VAR:
    2388             :             case PLPGSQL_DTYPE_REC:
    2389       13368 :                 n++;
    2390       13368 :                 break;
    2391             : 
    2392        8606 :             default:
    2393        8606 :                 break;
    2394             :         }
    2395             :     }
    2396             : 
    2397        6784 :     if (varnos != NULL)
    2398             :     {
    2399        3368 :         if (n > 0)
    2400             :         {
    2401        3368 :             *varnos = (int *) palloc(sizeof(int) * n);
    2402             : 
    2403        3368 :             n = 0;
    2404        9228 :             for (i = datums_last; i < plpgsql_nDatums; i++)
    2405             :             {
    2406        5860 :                 switch (plpgsql_Datums[i]->dtype)
    2407             :                 {
    2408        5788 :                     case PLPGSQL_DTYPE_VAR:
    2409             :                     case PLPGSQL_DTYPE_REC:
    2410        5788 :                         (*varnos)[n++] = plpgsql_Datums[i]->dno;
    2411             : 
    2412        5860 :                     default:
    2413        5860 :                         break;
    2414             :                 }
    2415             :             }
    2416             :         }
    2417             :         else
    2418           0 :             *varnos = NULL;
    2419             :     }
    2420             : 
    2421        6784 :     datums_last = plpgsql_nDatums;
    2422        6784 :     return n;
    2423             : }
    2424             : 
    2425             : 
    2426             : /*
    2427             :  * Compute the hashkey for a given function invocation
    2428             :  *
    2429             :  * The hashkey is returned into the caller-provided storage at *hashkey.
    2430             :  */
    2431             : static void
    2432       31440 : compute_function_hashkey(FunctionCallInfo fcinfo,
    2433             :                          Form_pg_proc procStruct,
    2434             :                          PLpgSQL_func_hashkey *hashkey,
    2435             :                          bool forValidator)
    2436             : {
    2437             :     /* Make sure any unused bytes of the struct are zero */
    2438     1666320 :     MemSet(hashkey, 0, sizeof(PLpgSQL_func_hashkey));
    2439             : 
    2440             :     /* get function OID */
    2441       31440 :     hashkey->funcOid = fcinfo->flinfo->fn_oid;
    2442             : 
    2443             :     /* get call context */
    2444       31440 :     hashkey->isTrigger = CALLED_AS_TRIGGER(fcinfo);
    2445       31440 :     hashkey->isEventTrigger = CALLED_AS_EVENT_TRIGGER(fcinfo);
    2446             : 
    2447             :     /*
    2448             :      * If DML trigger, include trigger's OID in the hash, so that each trigger
    2449             :      * usage gets a different hash entry, allowing for e.g. different relation
    2450             :      * rowtypes or transition table names.  In validation mode we do not know
    2451             :      * what relation or transition table names are intended to be used, so we
    2452             :      * leave trigOid zero; the hash entry built in this case will never be
    2453             :      * used for any actual calls.
    2454             :      *
    2455             :      * We don't currently need to distinguish different event trigger usages
    2456             :      * in the same way, since the special parameter variables don't vary in
    2457             :      * type in that case.
    2458             :      */
    2459       31440 :     if (hashkey->isTrigger && !forValidator)
    2460             :     {
    2461       12776 :         TriggerData *trigdata = (TriggerData *) fcinfo->context;
    2462             : 
    2463       12776 :         hashkey->trigOid = trigdata->tg_trigger->tgoid;
    2464             :     }
    2465             : 
    2466             :     /* get input collation, if known */
    2467       31440 :     hashkey->inputCollation = fcinfo->fncollation;
    2468             : 
    2469       31440 :     if (procStruct->pronargs > 0)
    2470             :     {
    2471             :         /* get the argument types */
    2472       13152 :         memcpy(hashkey->argtypes, procStruct->proargtypes.values,
    2473       13152 :                procStruct->pronargs * sizeof(Oid));
    2474             : 
    2475             :         /* resolve any polymorphic argument types */
    2476       13152 :         plpgsql_resolve_polymorphic_argtypes(procStruct->pronargs,
    2477       13152 :                                              hashkey->argtypes,
    2478             :                                              NULL,
    2479       13152 :                                              fcinfo->flinfo->fn_expr,
    2480             :                                              forValidator,
    2481       13152 :                                              NameStr(procStruct->proname));
    2482             :     }
    2483       31440 : }
    2484             : 
    2485             : /*
    2486             :  * This is the same as the standard resolve_polymorphic_argtypes() function,
    2487             :  * except that:
    2488             :  * 1. We go ahead and report the error if we can't resolve the types.
    2489             :  * 2. We treat RECORD-type input arguments (not output arguments) as if
    2490             :  *    they were polymorphic, replacing their types with the actual input
    2491             :  *    types if we can determine those.  This allows us to create a separate
    2492             :  *    function cache entry for each named composite type passed to such an
    2493             :  *    argument.
    2494             :  * 3. In validation mode, we have no inputs to look at, so assume that
    2495             :  *    polymorphic arguments are integer, integer-array or integer-range.
    2496             :  */
    2497             : static void
    2498       16826 : plpgsql_resolve_polymorphic_argtypes(int numargs,
    2499             :                                      Oid *argtypes, char *argmodes,
    2500             :                                      Node *call_expr, bool forValidator,
    2501             :                                      const char *proname)
    2502             : {
    2503             :     int         i;
    2504             : 
    2505       16826 :     if (!forValidator)
    2506             :     {
    2507             :         int         inargno;
    2508             : 
    2509             :         /* normal case, pass to standard routine */
    2510       12442 :         if (!resolve_polymorphic_argtypes(numargs, argtypes, argmodes,
    2511             :                                           call_expr))
    2512           0 :             ereport(ERROR,
    2513             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2514             :                      errmsg("could not determine actual argument "
    2515             :                             "type for polymorphic function \"%s\"",
    2516             :                             proname)));
    2517             :         /* also, treat RECORD inputs (but not outputs) as polymorphic */
    2518       12442 :         inargno = 0;
    2519       29940 :         for (i = 0; i < numargs; i++)
    2520             :         {
    2521       17498 :             char        argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
    2522             : 
    2523       17498 :             if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
    2524         120 :                 continue;
    2525       17378 :             if (argtypes[i] == RECORDOID || argtypes[i] == RECORDARRAYOID)
    2526             :             {
    2527          26 :                 Oid         resolvedtype = get_call_expr_argtype(call_expr,
    2528             :                                                                  inargno);
    2529             : 
    2530          26 :                 if (OidIsValid(resolvedtype))
    2531          26 :                     argtypes[i] = resolvedtype;
    2532             :             }
    2533       17378 :             inargno++;
    2534             :         }
    2535             :     }
    2536             :     else
    2537             :     {
    2538             :         /* special validation case (no need to do anything for RECORD) */
    2539        9714 :         for (i = 0; i < numargs; i++)
    2540             :         {
    2541        5330 :             switch (argtypes[i])
    2542             :             {
    2543         868 :                 case ANYELEMENTOID:
    2544             :                 case ANYNONARRAYOID:
    2545             :                 case ANYENUMOID:    /* XXX dubious */
    2546             :                 case ANYCOMPATIBLEOID:
    2547             :                 case ANYCOMPATIBLENONARRAYOID:
    2548         868 :                     argtypes[i] = INT4OID;
    2549         868 :                     break;
    2550         204 :                 case ANYARRAYOID:
    2551             :                 case ANYCOMPATIBLEARRAYOID:
    2552         204 :                     argtypes[i] = INT4ARRAYOID;
    2553         204 :                     break;
    2554          60 :                 case ANYRANGEOID:
    2555             :                 case ANYCOMPATIBLERANGEOID:
    2556          60 :                     argtypes[i] = INT4RANGEOID;
    2557          60 :                     break;
    2558           0 :                 case ANYMULTIRANGEOID:
    2559           0 :                     argtypes[i] = INT4MULTIRANGEOID;
    2560           0 :                     break;
    2561        4198 :                 default:
    2562        4198 :                     break;
    2563             :             }
    2564             :         }
    2565             :     }
    2566       16826 : }
    2567             : 
    2568             : /*
    2569             :  * delete_function - clean up as much as possible of a stale function cache
    2570             :  *
    2571             :  * We can't release the PLpgSQL_function struct itself, because of the
    2572             :  * possibility that there are fn_extra pointers to it.  We can release
    2573             :  * the subsidiary storage, but only if there are no active evaluations
    2574             :  * in progress.  Otherwise we'll just leak that storage.  Since the
    2575             :  * case would only occur if a pg_proc update is detected during a nested
    2576             :  * recursive call on the function, a leak seems acceptable.
    2577             :  *
    2578             :  * Note that this can be called more than once if there are multiple fn_extra
    2579             :  * pointers to the same function cache.  Hence be careful not to do things
    2580             :  * twice.
    2581             :  */
    2582             : static void
    2583         668 : delete_function(PLpgSQL_function *func)
    2584             : {
    2585             :     /* remove function from hash table (might be done already) */
    2586         668 :     plpgsql_HashTableDelete(func);
    2587             : 
    2588             :     /* release the function's storage if safe and not done already */
    2589         668 :     if (func->use_count == 0)
    2590         668 :         plpgsql_free_function_memory(func);
    2591         668 : }
    2592             : 
    2593             : /* exported so we can call it from _PG_init() */
    2594             : void
    2595        3364 : plpgsql_HashTableInit(void)
    2596             : {
    2597             :     HASHCTL     ctl;
    2598             : 
    2599             :     /* don't allow double-initialization */
    2600             :     Assert(plpgsql_HashTable == NULL);
    2601             : 
    2602        3364 :     ctl.keysize = sizeof(PLpgSQL_func_hashkey);
    2603        3364 :     ctl.entrysize = sizeof(plpgsql_HashEnt);
    2604        3364 :     plpgsql_HashTable = hash_create("PLpgSQL function hash",
    2605             :                                     FUNCS_PER_USER,
    2606             :                                     &ctl,
    2607             :                                     HASH_ELEM | HASH_BLOBS);
    2608        3364 : }
    2609             : 
    2610             : static PLpgSQL_function *
    2611       31440 : plpgsql_HashTableLookup(PLpgSQL_func_hashkey *func_key)
    2612             : {
    2613             :     plpgsql_HashEnt *hentry;
    2614             : 
    2615       31440 :     hentry = (plpgsql_HashEnt *) hash_search(plpgsql_HashTable,
    2616             :                                              func_key,
    2617             :                                              HASH_FIND,
    2618             :                                              NULL);
    2619       31440 :     if (hentry)
    2620       24440 :         return hentry->function;
    2621             :     else
    2622        7000 :         return NULL;
    2623             : }
    2624             : 
    2625             : static void
    2626        7546 : plpgsql_HashTableInsert(PLpgSQL_function *function,
    2627             :                         PLpgSQL_func_hashkey *func_key)
    2628             : {
    2629             :     plpgsql_HashEnt *hentry;
    2630             :     bool        found;
    2631             : 
    2632        7546 :     hentry = (plpgsql_HashEnt *) hash_search(plpgsql_HashTable,
    2633             :                                              func_key,
    2634             :                                              HASH_ENTER,
    2635             :                                              &found);
    2636        7546 :     if (found)
    2637           0 :         elog(WARNING, "trying to insert a function that already exists");
    2638             : 
    2639        7546 :     hentry->function = function;
    2640             :     /* prepare back link from function to hashtable key */
    2641        7546 :     function->fn_hashkey = &hentry->key;
    2642        7546 : }
    2643             : 
    2644             : static void
    2645         668 : plpgsql_HashTableDelete(PLpgSQL_function *function)
    2646             : {
    2647             :     plpgsql_HashEnt *hentry;
    2648             : 
    2649             :     /* do nothing if not in table */
    2650         668 :     if (function->fn_hashkey == NULL)
    2651           0 :         return;
    2652             : 
    2653         668 :     hentry = (plpgsql_HashEnt *) hash_search(plpgsql_HashTable,
    2654         668 :                                              function->fn_hashkey,
    2655             :                                              HASH_REMOVE,
    2656             :                                              NULL);
    2657         668 :     if (hentry == NULL)
    2658           0 :         elog(WARNING, "trying to delete function that does not exist");
    2659             : 
    2660             :     /* remove back link, which no longer points to allocated storage */
    2661         668 :     function->fn_hashkey = NULL;
    2662             : }

Generated by: LCOV version 1.14