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

Generated by: LCOV version 2.0-1