LCOV - code coverage report
Current view: top level - src/pl/plpgsql/src - pl_comp.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 725 778 93.2 %
Date: 2026-02-07 10:18:48 Functions: 32 32 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pl_comp.c        - Compiler part of the PL/pgSQL
       4             :  *            procedural language
       5             :  *
       6             :  * Portions Copyright (c) 1996-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       89882 : 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       89882 :         cached_function_compile(fcinfo,
     120       89882 :                                 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       89760 :     fcinfo->flinfo->fn_extra = function;
     131             : 
     132             :     /*
     133             :      * Finally return the compiled function
     134             :      */
     135       89760 :     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        8282 : plpgsql_compile_callback(FunctionCallInfo fcinfo,
     168             :                          HeapTuple procTup,
     169             :                          const CachedFunctionHashKey *hashkey,
     170             :                          CachedFunction *cfunc,
     171             :                          bool forValidator)
     172             : {
     173        8282 :     PLpgSQL_function *function = (PLpgSQL_function *) cfunc;
     174        8282 :     Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
     175        8282 :     bool        is_dml_trigger = CALLED_AS_TRIGGER(fcinfo);
     176        8282 :     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        8282 :     int         num_in_args = 0;
     192        8282 :     int         num_out_args = 0;
     193             :     Oid        *argtypes;
     194             :     char      **argnames;
     195             :     char       *argmodes;
     196        8282 :     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        8282 :     prosrcdatum = SysCacheGetAttrNotNull(PROCOID, procTup, Anum_pg_proc_prosrc);
     204        8282 :     proc_source = TextDatumGetCString(prosrcdatum);
     205        8282 :     scanner = plpgsql_scanner_init(proc_source);
     206             : 
     207        8282 :     plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));
     208             : 
     209             :     /*
     210             :      * Setup error traceback support for ereport()
     211             :      */
     212        8282 :     cbarg.proc_source = forValidator ? proc_source : NULL;
     213        8282 :     cbarg.yyscanner = scanner;
     214        8282 :     plerrcontext.callback = plpgsql_compile_error_callback;
     215        8282 :     plerrcontext.arg = &cbarg;
     216        8282 :     plerrcontext.previous = error_context_stack;
     217        8282 :     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        8282 :     plpgsql_check_syntax = forValidator;
     225        8282 :     plpgsql_curr_compile = function;
     226             : 
     227             :     /* format_procedure leaks memory, so run it in temp context */
     228        8282 :     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        8282 :     func_cxt = AllocSetContextCreate(CurrentMemoryContext,
     240             :                                      "PL/pgSQL function",
     241             :                                      ALLOCSET_DEFAULT_SIZES);
     242        8282 :     plpgsql_compile_tmp_cxt = MemoryContextSwitchTo(func_cxt);
     243             : 
     244        8282 :     function->fn_signature = pstrdup(proc_signature);
     245        8282 :     MemoryContextSetIdentifier(func_cxt, function->fn_signature);
     246        8282 :     function->fn_oid = fcinfo->flinfo->fn_oid;
     247        8282 :     function->fn_input_collation = fcinfo->fncollation;
     248        8282 :     function->fn_cxt = func_cxt;
     249        8282 :     function->out_param_varno = -1; /* set up for no OUT param */
     250        8282 :     function->resolve_option = plpgsql_variable_conflict;
     251        8282 :     function->print_strict_params = plpgsql_print_strict_params;
     252             :     /* only promote extra warnings and errors at CREATE FUNCTION time */
     253        8282 :     function->extra_warnings = forValidator ? plpgsql_extra_warnings : 0;
     254        8282 :     function->extra_errors = forValidator ? plpgsql_extra_errors : 0;
     255             : 
     256        8282 :     if (is_dml_trigger)
     257        3828 :         function->fn_is_trigger = PLPGSQL_DML_TRIGGER;
     258        4454 :     else if (is_event_trigger)
     259         430 :         function->fn_is_trigger = PLPGSQL_EVENT_TRIGGER;
     260             :     else
     261        4024 :         function->fn_is_trigger = PLPGSQL_NOT_TRIGGER;
     262             : 
     263        8282 :     function->fn_prokind = procStruct->prokind;
     264             : 
     265        8282 :     function->nstatements = 0;
     266        8282 :     function->requires_procedure_resowner = false;
     267        8282 :     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        8282 :     plpgsql_ns_init();
     275        8282 :     plpgsql_ns_push(NameStr(procStruct->proname), PLPGSQL_LABEL_BLOCK);
     276        8282 :     plpgsql_DumpExecTree = false;
     277        8282 :     plpgsql_start_datums();
     278             : 
     279        8282 :     switch (function->fn_is_trigger)
     280             :     {
     281        4024 :         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        4024 :             MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
     292             : 
     293        4024 :             numargs = get_func_arg_info(procTup,
     294             :                                         &argtypes, &argnames, &argmodes);
     295             : 
     296        4024 :             cfunc_resolve_polymorphic_argtypes(numargs, argtypes, argmodes,
     297        4024 :                                                fcinfo->flinfo->fn_expr,
     298             :                                                forValidator,
     299             :                                                plpgsql_error_funcname);
     300             : 
     301        4024 :             in_arg_varnos = palloc_array(int, numargs);
     302        4024 :             out_arg_variables = palloc_array(PLpgSQL_variable *, numargs);
     303             : 
     304        4024 :             MemoryContextSwitchTo(func_cxt);
     305             : 
     306             :             /*
     307             :              * Create the variables for the procedure's parameters.
     308             :              */
     309        9006 :             for (i = 0; i < numargs; i++)
     310             :             {
     311             :                 char        buf[32];
     312        4988 :                 Oid         argtypeid = argtypes[i];
     313        4988 :                 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        4988 :                 snprintf(buf, sizeof(buf), "$%d", i + 1);
     320             : 
     321             :                 /* Create datatype info */
     322        4988 :                 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        4988 :                 if (argdtype->ttype == PLPGSQL_TTYPE_PSEUDO)
     331           6 :                     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        8616 :                 argvariable = plpgsql_build_variable((argnames &&
     341        3634 :                                                       argnames[i][0] != '\0') ?
     342        3610 :                                                      argnames[i] : buf,
     343             :                                                      0, argdtype, false);
     344             : 
     345        4982 :                 if (argvariable->dtype == PLPGSQL_DTYPE_VAR)
     346             :                 {
     347        4900 :                     argitemtype = PLPGSQL_NSTYPE_VAR;
     348             :                 }
     349             :                 else
     350             :                 {
     351             :                     Assert(argvariable->dtype == PLPGSQL_DTYPE_REC);
     352          82 :                     argitemtype = PLPGSQL_NSTYPE_REC;
     353             :                 }
     354             : 
     355             :                 /* Remember arguments in appropriate arrays */
     356        4982 :                 if (argmode == PROARGMODE_IN ||
     357         450 :                     argmode == PROARGMODE_INOUT ||
     358             :                     argmode == PROARGMODE_VARIADIC)
     359        4546 :                     in_arg_varnos[num_in_args++] = argvariable->dno;
     360        4982 :                 if (argmode == PROARGMODE_OUT ||
     361        4654 :                     argmode == PROARGMODE_INOUT ||
     362             :                     argmode == PROARGMODE_TABLE)
     363         484 :                     out_arg_variables[num_out_args++] = argvariable;
     364             : 
     365             :                 /* Add to namespace under the $n name */
     366        4982 :                 add_parameter_name(argitemtype, argvariable->dno, buf);
     367             : 
     368             :                 /* If there's a name for the argument, make an alias */
     369        4982 :                 if (argnames && argnames[i][0] != '\0')
     370        3610 :                     add_parameter_name(argitemtype, argvariable->dno,
     371        3610 :                                        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        4018 :             if (num_out_args > 1 ||
     381          78 :                 (num_out_args == 1 && function->fn_prokind == PROKIND_PROCEDURE))
     382         192 :             {
     383         192 :                 PLpgSQL_row *row = build_row_from_vars(out_arg_variables,
     384             :                                                        num_out_args);
     385             : 
     386         192 :                 plpgsql_adddatum((PLpgSQL_datum *) row);
     387         192 :                 function->out_param_varno = row->dno;
     388             :             }
     389        3826 :             else if (num_out_args == 1)
     390          60 :                 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        4018 :             rettypeid = procStruct->prorettype;
     403        4018 :             if (IsPolymorphicType(rettypeid))
     404             :             {
     405         144 :                 if (forValidator)
     406             :                 {
     407          72 :                     if (rettypeid == ANYARRAYOID ||
     408             :                         rettypeid == ANYCOMPATIBLEARRAYOID)
     409          48 :                         rettypeid = INT4ARRAYOID;
     410          24 :                     else if (rettypeid == ANYRANGEOID ||
     411             :                              rettypeid == ANYCOMPATIBLERANGEOID)
     412           6 :                         rettypeid = INT4RANGEOID;
     413          18 :                     else if (rettypeid == ANYMULTIRANGEOID)
     414           6 :                         rettypeid = INT4MULTIRANGEOID;
     415             :                     else        /* ANYELEMENT or ANYNONARRAY or ANYCOMPATIBLE */
     416          12 :                         rettypeid = INT4OID;
     417             :                     /* XXX what could we use for ANYENUM? */
     418             :                 }
     419             :                 else
     420             :                 {
     421          72 :                     rettypeid = get_fn_expr_rettype(fcinfo->flinfo);
     422          72 :                     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        4018 :             function->fn_rettype = rettypeid;
     435        4018 :             function->fn_retset = procStruct->proretset;
     436             : 
     437             :             /*
     438             :              * Lookup the function's return type
     439             :              */
     440        4018 :             typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettypeid));
     441        4018 :             if (!HeapTupleIsValid(typeTup))
     442           0 :                 elog(ERROR, "cache lookup failed for type %u", rettypeid);
     443        4018 :             typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
     444             : 
     445             :             /* Disallow pseudotype result, except VOID or RECORD */
     446             :             /* (note we already replaced polymorphic types) */
     447        4018 :             if (typeStruct->typtype == TYPTYPE_PSEUDO)
     448             :             {
     449        1510 :                 if (rettypeid == VOIDOID ||
     450             :                     rettypeid == RECORDOID)
     451             :                      /* okay */ ;
     452           6 :                 else if (rettypeid == TRIGGEROID || rettypeid == EVENT_TRIGGEROID)
     453           6 :                     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        4012 :             function->fn_retistuple = type_is_rowtype(rettypeid);
     464        4012 :             function->fn_retisdomain = (typeStruct->typtype == TYPTYPE_DOMAIN);
     465        4012 :             function->fn_retbyval = typeStruct->typbyval;
     466        4012 :             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        4012 :             if (IsPolymorphicType(procStruct->prorettype) &&
     474             :                 num_out_args == 0)
     475             :             {
     476         144 :                 (void) plpgsql_build_variable("$0", 0,
     477             :                                               build_datatype(typeTup,
     478             :                                                              -1,
     479             :                                                              function->fn_input_collation,
     480             :                                                              NULL),
     481             :                                               true);
     482             :             }
     483             : 
     484        4012 :             ReleaseSysCache(typeTup);
     485        4012 :             break;
     486             : 
     487        3828 :         case PLPGSQL_DML_TRIGGER:
     488             :             /* Trigger procedure's return type is unknown yet */
     489        3828 :             function->fn_rettype = InvalidOid;
     490        3828 :             function->fn_retbyval = false;
     491        3828 :             function->fn_retistuple = true;
     492        3828 :             function->fn_retisdomain = false;
     493        3828 :             function->fn_retset = false;
     494             : 
     495             :             /* shouldn't be any declared arguments */
     496        3828 :             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        3828 :             rec = plpgsql_build_record("new", 0, NULL, RECORDOID, true);
     504        3828 :             function->new_varno = rec->dno;
     505             : 
     506             :             /* Add the record for referencing OLD ROW */
     507        3828 :             rec = plpgsql_build_record("old", 0, NULL, RECORDOID, true);
     508        3828 :             function->old_varno = rec->dno;
     509             : 
     510             :             /* Add the variable tg_name */
     511        3828 :             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        3828 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     519        3828 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_NAME;
     520             : 
     521             :             /* Add the variable tg_when */
     522        3828 :             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        3828 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     530        3828 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_WHEN;
     531             : 
     532             :             /* Add the variable tg_level */
     533        3828 :             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        3828 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     541        3828 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_LEVEL;
     542             : 
     543             :             /* Add the variable tg_op */
     544        3828 :             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        3828 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     552        3828 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_OP;
     553             : 
     554             :             /* Add the variable tg_relid */
     555        3828 :             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        3828 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     563        3828 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_RELID;
     564             : 
     565             :             /* Add the variable tg_relname */
     566        3828 :             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        3828 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     574        3828 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_TABLE_NAME;
     575             : 
     576             :             /* tg_table_name is now preferred to tg_relname */
     577        3828 :             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        3828 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     585        3828 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_TABLE_NAME;
     586             : 
     587             :             /* add the variable tg_table_schema */
     588        3828 :             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        3828 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     596        3828 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_TABLE_SCHEMA;
     597             : 
     598             :             /* Add the variable tg_nargs */
     599        3828 :             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        3828 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     607        3828 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_NARGS;
     608             : 
     609             :             /* Add the variable tg_argv */
     610        3828 :             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        3828 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     618        3828 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_ARGV;
     619             : 
     620        3828 :             break;
     621             : 
     622         430 :         case PLPGSQL_EVENT_TRIGGER:
     623         430 :             function->fn_rettype = VOIDOID;
     624         430 :             function->fn_retbyval = false;
     625         430 :             function->fn_retistuple = true;
     626         430 :             function->fn_retisdomain = false;
     627         430 :             function->fn_retset = false;
     628             : 
     629             :             /* shouldn't be any declared arguments */
     630         430 :             if (procStruct->pronargs != 0)
     631           6 :                 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         424 :             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         424 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     644         424 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_EVENT;
     645             : 
     646             :             /* Add the variable tg_tag */
     647         424 :             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         424 :             var->dtype = PLPGSQL_DTYPE_PROMISE;
     655         424 :             ((PLpgSQL_var *) var)->promise = PLPGSQL_PROMISE_TG_TAG;
     656             : 
     657         424 :             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        8264 :     function->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
     667             : 
     668             :     /*
     669             :      * Create the magic FOUND variable.
     670             :      */
     671        8264 :     var = plpgsql_build_variable("found", 0,
     672             :                                  plpgsql_build_datatype(BOOLOID,
     673             :                                                         -1,
     674             :                                                         InvalidOid,
     675             :                                                         NULL),
     676             :                                  true);
     677        8264 :     function->found_varno = var->dno;
     678             : 
     679             :     /*
     680             :      * Now parse the function's text
     681             :      */
     682        8264 :     parse_rc = plpgsql_yyparse(&function->action, scanner);
     683        8160 :     if (parse_rc != 0)
     684           0 :         elog(ERROR, "plpgsql parser returned %d", parse_rc);
     685             : 
     686        8160 :     plpgsql_scanner_finish(scanner);
     687        8160 :     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        8160 :     if (num_out_args > 0 || function->fn_rettype == VOIDOID ||
     696        6294 :         function->fn_retset)
     697        2188 :         add_dummy_return(function);
     698             : 
     699             :     /*
     700             :      * Complete the function's info
     701             :      */
     702        8160 :     function->fn_nargs = procStruct->pronargs;
     703       12674 :     for (i = 0; i < function->fn_nargs; i++)
     704        4514 :         function->fn_argvarnos[i] = in_arg_varnos[i];
     705             : 
     706        8160 :     plpgsql_finish_datums(function);
     707             : 
     708        8160 :     if (function->has_exception_block)
     709         358 :         plpgsql_mark_local_assignment_targets(function);
     710             : 
     711             :     /* Debug dump for completed functions */
     712        8160 :     if (plpgsql_DumpExecTree)
     713           0 :         plpgsql_dumptree(function);
     714             : 
     715             :     /*
     716             :      * All is well, so make the func_cxt long-lived
     717             :      */
     718        8160 :     MemoryContextSetParent(func_cxt, CacheMemoryContext);
     719             : 
     720             :     /*
     721             :      * Pop the error context stack
     722             :      */
     723        8160 :     error_context_stack = plerrcontext.previous;
     724        8160 :     plpgsql_error_funcname = NULL;
     725             : 
     726        8160 :     plpgsql_check_syntax = false;
     727             : 
     728        8160 :     MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
     729        8160 :     plpgsql_compile_tmp_cxt = NULL;
     730        8160 : }
     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        1514 : plpgsql_compile_inline(char *proc_source)
     744             : {
     745             :     yyscan_t    scanner;
     746        1514 :     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        1514 :     scanner = plpgsql_scanner_init(proc_source);
     758             : 
     759        1514 :     plpgsql_error_funcname = func_name;
     760             : 
     761             :     /*
     762             :      * Setup error traceback support for ereport()
     763             :      */
     764        1514 :     cbarg.proc_source = proc_source;
     765        1514 :     cbarg.yyscanner = scanner;
     766        1514 :     plerrcontext.callback = plpgsql_compile_error_callback;
     767        1514 :     plerrcontext.arg = &cbarg;
     768        1514 :     plerrcontext.previous = error_context_stack;
     769        1514 :     error_context_stack = &plerrcontext;
     770             : 
     771             :     /* Do extra syntax checking if check_function_bodies is on */
     772        1514 :     plpgsql_check_syntax = check_function_bodies;
     773             : 
     774             :     /* Function struct does not live past current statement */
     775        1514 :     function = palloc0_object(PLpgSQL_function);
     776             : 
     777        1514 :     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        1514 :     func_cxt = AllocSetContextCreate(CurrentMemoryContext,
     784             :                                      "PL/pgSQL inline code context",
     785             :                                      ALLOCSET_DEFAULT_SIZES);
     786        1514 :     plpgsql_compile_tmp_cxt = MemoryContextSwitchTo(func_cxt);
     787             : 
     788        1514 :     function->fn_signature = pstrdup(func_name);
     789        1514 :     function->fn_is_trigger = PLPGSQL_NOT_TRIGGER;
     790        1514 :     function->fn_input_collation = InvalidOid;
     791        1514 :     function->fn_cxt = func_cxt;
     792        1514 :     function->out_param_varno = -1; /* set up for no OUT param */
     793        1514 :     function->resolve_option = plpgsql_variable_conflict;
     794        1514 :     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        1514 :     function->extra_warnings = 0;
     801        1514 :     function->extra_errors = 0;
     802             : 
     803        1514 :     function->nstatements = 0;
     804        1514 :     function->requires_procedure_resowner = false;
     805        1514 :     function->has_exception_block = false;
     806             : 
     807        1514 :     plpgsql_ns_init();
     808        1514 :     plpgsql_ns_push(func_name, PLPGSQL_LABEL_BLOCK);
     809        1514 :     plpgsql_DumpExecTree = false;
     810        1514 :     plpgsql_start_datums();
     811             : 
     812             :     /* Set up as though in a function returning VOID */
     813        1514 :     function->fn_rettype = VOIDOID;
     814        1514 :     function->fn_retset = false;
     815        1514 :     function->fn_retistuple = false;
     816        1514 :     function->fn_retisdomain = false;
     817        1514 :     function->fn_prokind = PROKIND_FUNCTION;
     818             :     /* a bit of hardwired knowledge about type VOID here */
     819        1514 :     function->fn_retbyval = true;
     820        1514 :     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        1514 :     function->fn_readonly = false;
     827             : 
     828             :     /*
     829             :      * Create the magic FOUND variable.
     830             :      */
     831        1514 :     var = plpgsql_build_variable("found", 0,
     832             :                                  plpgsql_build_datatype(BOOLOID,
     833             :                                                         -1,
     834             :                                                         InvalidOid,
     835             :                                                         NULL),
     836             :                                  true);
     837        1514 :     function->found_varno = var->dno;
     838             : 
     839             :     /*
     840             :      * Now parse the function's text
     841             :      */
     842        1514 :     parse_rc = plpgsql_yyparse(&function->action, scanner);
     843        1458 :     if (parse_rc != 0)
     844           0 :         elog(ERROR, "plpgsql parser returned %d", parse_rc);
     845             : 
     846        1458 :     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        1458 :     if (function->fn_rettype == VOIDOID)
     853        1458 :         add_dummy_return(function);
     854             : 
     855             :     /*
     856             :      * Complete the function's info
     857             :      */
     858        1458 :     function->fn_nargs = 0;
     859             : 
     860        1458 :     plpgsql_finish_datums(function);
     861             : 
     862        1458 :     if (function->has_exception_block)
     863          84 :         plpgsql_mark_local_assignment_targets(function);
     864             : 
     865             :     /* Debug dump for completed functions */
     866        1458 :     if (plpgsql_DumpExecTree)
     867           0 :         plpgsql_dumptree(function);
     868             : 
     869             :     /*
     870             :      * Pop the error context stack
     871             :      */
     872        1458 :     error_context_stack = plerrcontext.previous;
     873        1458 :     plpgsql_error_funcname = NULL;
     874             : 
     875        1458 :     plpgsql_check_syntax = false;
     876             : 
     877        1458 :     MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
     878        1458 :     plpgsql_compile_tmp_cxt = NULL;
     879        1458 :     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         226 : plpgsql_compile_error_callback(void *arg)
     890             : {
     891         226 :     struct compile_error_callback_arg *cbarg = (struct compile_error_callback_arg *) arg;
     892         226 :     yyscan_t    yyscanner = cbarg->yyscanner;
     893             : 
     894         226 :     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         212 :         if (function_parse_error_transpose(cbarg->proc_source))
     901         166 :             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          60 :     if (plpgsql_error_funcname)
     910          60 :         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        8592 : 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        8592 :     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        8592 :     plpgsql_ns_additem(itemtype, itemno, name);
     938        8592 : }
     939             : 
     940             : /*
     941             :  * Add a dummy RETURN statement to the given function's body
     942             :  */
     943             : static void
     944        3646 : 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        3646 :     if (function->action->exceptions != NULL ||
     953        3384 :         function->action->label != NULL)
     954             :     {
     955             :         PLpgSQL_stmt_block *new;
     956             : 
     957         288 :         new = palloc0_object(PLpgSQL_stmt_block);
     958         288 :         new->cmd_type = PLPGSQL_STMT_BLOCK;
     959         288 :         new->stmtid = ++function->nstatements;
     960         288 :         new->body = list_make1(function->action);
     961             : 
     962         288 :         function->action = new;
     963             :     }
     964        3646 :     if (function->action->body == NIL ||
     965        3592 :         ((PLpgSQL_stmt *) llast(function->action->body))->cmd_type != PLPGSQL_STMT_RETURN)
     966             :     {
     967             :         PLpgSQL_stmt_return *new;
     968             : 
     969        3536 :         new = palloc0_object(PLpgSQL_stmt_return);
     970        3536 :         new->cmd_type = PLPGSQL_STMT_RETURN;
     971        3536 :         new->stmtid = ++function->nstatements;
     972        3536 :         new->expr = NULL;
     973        3536 :         new->retvarno = function->out_param_varno;
     974             : 
     975        3536 :         function->action->body = lappend(function->action->body, new);
     976             :     }
     977        3646 : }
     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       34070 : plpgsql_parser_setup(struct ParseState *pstate, PLpgSQL_expr *expr)
     990             : {
     991       34070 :     pstate->p_pre_columnref_hook = plpgsql_pre_column_ref;
     992       34070 :     pstate->p_post_columnref_hook = plpgsql_post_column_ref;
     993       34070 :     pstate->p_paramref_hook = plpgsql_param_ref;
     994             :     /* no need to use p_coerce_param_hook */
     995       34070 :     pstate->p_ref_hook_state = expr;
     996       34070 : }
     997             : 
     998             : /*
     999             :  * plpgsql_pre_column_ref       parser callback before parsing a ColumnRef
    1000             :  */
    1001             : static Node *
    1002       37528 : plpgsql_pre_column_ref(ParseState *pstate, ColumnRef *cref)
    1003             : {
    1004       37528 :     PLpgSQL_expr *expr = (PLpgSQL_expr *) pstate->p_ref_hook_state;
    1005             : 
    1006       37528 :     if (expr->func->resolve_option == PLPGSQL_RESOLVE_VARIABLE)
    1007          12 :         return resolve_column_ref(pstate, expr, cref, false);
    1008             :     else
    1009       37516 :         return NULL;
    1010             : }
    1011             : 
    1012             : /*
    1013             :  * plpgsql_post_column_ref      parser callback after parsing a ColumnRef
    1014             :  */
    1015             : static Node *
    1016       37522 : plpgsql_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var)
    1017             : {
    1018       37522 :     PLpgSQL_expr *expr = (PLpgSQL_expr *) pstate->p_ref_hook_state;
    1019             :     Node       *myvar;
    1020             : 
    1021       37522 :     if (expr->func->resolve_option == PLPGSQL_RESOLVE_VARIABLE)
    1022           6 :         return NULL;            /* we already found there's no match */
    1023             : 
    1024       37516 :     if (expr->func->resolve_option == PLPGSQL_RESOLVE_COLUMN && var != NULL)
    1025          12 :         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       37504 :     myvar = resolve_column_ref(pstate, expr, cref, (var == NULL));
    1038             : 
    1039       37480 :     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          12 :         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       37468 :     return myvar;
    1054             : }
    1055             : 
    1056             : /*
    1057             :  * plpgsql_param_ref        parser callback for ParamRefs ($n symbols)
    1058             :  */
    1059             : static Node *
    1060        1158 : plpgsql_param_ref(ParseState *pstate, ParamRef *pref)
    1061             : {
    1062        1158 :     PLpgSQL_expr *expr = (PLpgSQL_expr *) pstate->p_ref_hook_state;
    1063             :     char        pname[32];
    1064             :     PLpgSQL_nsitem *nse;
    1065             : 
    1066        1158 :     snprintf(pname, sizeof(pname), "$%d", pref->number);
    1067             : 
    1068        1158 :     nse = plpgsql_ns_lookup(expr->ns, false,
    1069             :                             pname, NULL, NULL,
    1070             :                             NULL);
    1071             : 
    1072        1158 :     if (nse == NULL)
    1073           0 :         return NULL;            /* name not known to plpgsql */
    1074             : 
    1075        1158 :     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       37516 : 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       37516 :     const char *name2 = NULL;
    1094       37516 :     const char *name3 = NULL;
    1095       37516 :     const char *colname = NULL;
    1096             :     int         nnames;
    1097       37516 :     int         nnames_scalar = 0;
    1098       37516 :     int         nnames_wholerow = 0;
    1099       37516 :     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       37516 :     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       37516 :     switch (list_length(cref->fields))
    1119             :     {
    1120       31738 :         case 1:
    1121             :             {
    1122       31738 :                 Node       *field1 = (Node *) linitial(cref->fields);
    1123             : 
    1124       31738 :                 name1 = strVal(field1);
    1125       31738 :                 nnames_scalar = 1;
    1126       31738 :                 nnames_wholerow = 1;
    1127       31738 :                 break;
    1128             :             }
    1129        5748 :         case 2:
    1130             :             {
    1131        5748 :                 Node       *field1 = (Node *) linitial(cref->fields);
    1132        5748 :                 Node       *field2 = (Node *) lsecond(cref->fields);
    1133             : 
    1134        5748 :                 name1 = strVal(field1);
    1135             : 
    1136             :                 /* Whole-row reference? */
    1137        5748 :                 if (IsA(field2, A_Star))
    1138             :                 {
    1139             :                     /* Set name2 to prevent matches to scalar variables */
    1140         100 :                     name2 = "*";
    1141         100 :                     nnames_wholerow = 1;
    1142         100 :                     break;
    1143             :                 }
    1144             : 
    1145        5648 :                 name2 = strVal(field2);
    1146        5648 :                 colname = name2;
    1147        5648 :                 nnames_scalar = 2;
    1148        5648 :                 nnames_wholerow = 2;
    1149        5648 :                 nnames_field = 1;
    1150        5648 :                 break;
    1151             :             }
    1152          30 :         case 3:
    1153             :             {
    1154          30 :                 Node       *field1 = (Node *) linitial(cref->fields);
    1155          30 :                 Node       *field2 = (Node *) lsecond(cref->fields);
    1156          30 :                 Node       *field3 = (Node *) lthird(cref->fields);
    1157             : 
    1158          30 :                 name1 = strVal(field1);
    1159          30 :                 name2 = strVal(field2);
    1160             : 
    1161             :                 /* Whole-row reference? */
    1162          30 :                 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          30 :                 name3 = strVal(field3);
    1171          30 :                 colname = name3;
    1172          30 :                 nnames_field = 2;
    1173          30 :                 break;
    1174             :             }
    1175           0 :         default:
    1176             :             /* too many names, ignore */
    1177           0 :             return NULL;
    1178             :     }
    1179             : 
    1180       37516 :     nse = plpgsql_ns_lookup(expr->ns, false,
    1181             :                             name1, name2, name3,
    1182             :                             &nnames);
    1183             : 
    1184       37516 :     if (nse == NULL)
    1185        4268 :         return NULL;            /* name not known to plpgsql */
    1186             : 
    1187       33248 :     switch (nse->itemtype)
    1188             :     {
    1189       25470 :         case PLPGSQL_NSTYPE_VAR:
    1190       25470 :             if (nnames == nnames_scalar)
    1191       25470 :                 return make_datum_param(expr, nse->itemno, cref->location);
    1192           0 :             break;
    1193        7778 :         case PLPGSQL_NSTYPE_REC:
    1194        7778 :             if (nnames == nnames_wholerow)
    1195        2620 :                 return make_datum_param(expr, nse->itemno, cref->location);
    1196        5158 :             if (nnames == nnames_field)
    1197             :             {
    1198             :                 /* colname could be a field in this record */
    1199        5158 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) estate->datums[nse->itemno];
    1200             :                 int         i;
    1201             : 
    1202             :                 /* search for a datum referencing this field */
    1203        5158 :                 i = rec->firstfield;
    1204       13208 :                 while (i >= 0)
    1205             :                 {
    1206       13206 :                     PLpgSQL_recfield *fld = (PLpgSQL_recfield *) estate->datums[i];
    1207             : 
    1208             :                     Assert(fld->dtype == PLPGSQL_DTYPE_RECFIELD &&
    1209             :                            fld->recparentno == nse->itemno);
    1210       13206 :                     if (strcmp(fld->fieldname, colname) == 0)
    1211             :                     {
    1212        5156 :                         return make_datum_param(expr, i, cref->location);
    1213             :                     }
    1214        8050 :                     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           2 :                 if (error_if_no_field)
    1229           2 :                     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       34404 : 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       34404 :     estate = expr->func->cur_estate;
    1259             :     Assert(dno >= 0 && dno < estate->ndatums);
    1260       34404 :     datum = estate->datums[dno];
    1261             : 
    1262             :     /*
    1263             :      * Bitmapset must be allocated in function's permanent memory context
    1264             :      */
    1265       34404 :     oldcontext = MemoryContextSwitchTo(expr->func->fn_cxt);
    1266       34404 :     expr->paramnos = bms_add_member(expr->paramnos, dno);
    1267       34404 :     MemoryContextSwitchTo(oldcontext);
    1268             : 
    1269       34404 :     param = makeNode(Param);
    1270       34404 :     param->paramkind = PARAM_EXTERN;
    1271       34404 :     param->paramid = dno + 1;
    1272       34404 :     plpgsql_exec_get_datum_type_info(estate,
    1273             :                                      datum,
    1274             :                                      &param->paramtype,
    1275             :                                      &param->paramtypmod,
    1276             :                                      &param->paramcollid);
    1277       34382 :     param->location = location;
    1278             : 
    1279       34382 :     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      131428 : 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      131428 :     if (lookup && plpgsql_IdentifierLookup == IDENTIFIER_LOOKUP_NORMAL)
    1314             :     {
    1315             :         /*
    1316             :          * Do a lookup in the current namespace stack
    1317             :          */
    1318       29592 :         ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
    1319             :                                word1, NULL, NULL,
    1320             :                                NULL);
    1321             : 
    1322       29592 :         if (ns != NULL)
    1323             :         {
    1324       15962 :             switch (ns->itemtype)
    1325             :             {
    1326       15962 :                 case PLPGSQL_NSTYPE_VAR:
    1327             :                 case PLPGSQL_NSTYPE_REC:
    1328       15962 :                     wdatum->datum = plpgsql_Datums[ns->itemno];
    1329       15962 :                     wdatum->ident = word1;
    1330       15962 :                     wdatum->quoted = (yytxt[0] == '"');
    1331       15962 :                     wdatum->idents = NIL;
    1332       15962 :                     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      115466 :     word->ident = word1;
    1347      115466 :     word->quoted = (yytxt[0] == '"');
    1348      115466 :     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        8432 : 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        8432 :     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        8432 :     if (plpgsql_IdentifierLookup != IDENTIFIER_LOOKUP_DECLARE)
    1375             :     {
    1376             :         /*
    1377             :          * Do a lookup in the current namespace stack
    1378             :          */
    1379        8374 :         ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
    1380             :                                word1, word2, NULL,
    1381             :                                &nnames);
    1382        8374 :         if (ns != NULL)
    1383             :         {
    1384        7440 :             switch (ns->itemtype)
    1385             :             {
    1386          24 :                 case PLPGSQL_NSTYPE_VAR:
    1387             :                     /* Block-qualified reference to scalar variable. */
    1388          24 :                     wdatum->datum = plpgsql_Datums[ns->itemno];
    1389          24 :                     wdatum->ident = NULL;
    1390          24 :                     wdatum->quoted = false; /* not used */
    1391          24 :                     wdatum->idents = idents;
    1392          24 :                     return true;
    1393             : 
    1394        7416 :                 case PLPGSQL_NSTYPE_REC:
    1395        7416 :                     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        7400 :                         rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]);
    1407        7400 :                         new = plpgsql_build_recfield(rec, word2);
    1408             : 
    1409        7400 :                         wdatum->datum = (PLpgSQL_datum *) new;
    1410             :                     }
    1411             :                     else
    1412             :                     {
    1413             :                         /* Block-qualified reference to record variable. */
    1414          16 :                         wdatum->datum = plpgsql_Datums[ns->itemno];
    1415             :                     }
    1416        7416 :                     wdatum->ident = NULL;
    1417        7416 :                     wdatum->quoted = false; /* not used */
    1418        7416 :                     wdatum->idents = idents;
    1419        7416 :                     return true;
    1420             : 
    1421           0 :                 default:
    1422           0 :                     break;
    1423             :             }
    1424             :         }
    1425             :     }
    1426             : 
    1427             :     /* Nothing found */
    1428         992 :     cword->idents = idents;
    1429         992 :     return false;
    1430             : }
    1431             : 
    1432             : 
    1433             : /* ----------
    1434             :  * plpgsql_parse_tripword       Same lookup for three words
    1435             :  *                  separated by dots.
    1436             :  * ----------
    1437             :  */
    1438             : bool
    1439          60 : 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          60 :     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          46 :         ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
    1460             :                                word1, word2, word3,
    1461             :                                &nnames);
    1462          46 :         if (ns != NULL)
    1463             :         {
    1464          42 :             switch (ns->itemtype)
    1465             :             {
    1466          42 :                 case PLPGSQL_NSTYPE_REC:
    1467             :                     {
    1468             :                         PLpgSQL_rec *rec;
    1469             :                         PLpgSQL_recfield *new;
    1470             : 
    1471          42 :                         rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]);
    1472          42 :                         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           6 :                             new = plpgsql_build_recfield(rec, word2);
    1482           6 :                             idents = list_make2(makeString(word1),
    1483             :                                                 makeString(word2));
    1484             :                         }
    1485             :                         else
    1486             :                         {
    1487             :                             /* Block-qualified reference to record variable. */
    1488          36 :                             new = plpgsql_build_recfield(rec, word3);
    1489          36 :                             idents = list_make3(makeString(word1),
    1490             :                                                 makeString(word2),
    1491             :                                                 makeString(word3));
    1492             :                         }
    1493          42 :                         wdatum->datum = (PLpgSQL_datum *) new;
    1494          42 :                         wdatum->ident = NULL;
    1495          42 :                         wdatum->quoted = false; /* not used */
    1496          42 :                         wdatum->idents = idents;
    1497          42 :                         return true;
    1498             :                     }
    1499             : 
    1500           0 :                 default:
    1501           0 :                     break;
    1502             :             }
    1503             :         }
    1504             :     }
    1505             : 
    1506             :     /* Nothing found */
    1507          18 :     idents = list_make3(makeString(word1),
    1508             :                         makeString(word2),
    1509             :                         makeString(word3));
    1510          18 :     cword->idents = idents;
    1511          18 :     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          48 : plpgsql_parse_wordtype(char *ident)
    1524             : {
    1525             :     PLpgSQL_nsitem *nse;
    1526             : 
    1527             :     /*
    1528             :      * Do a lookup in the current namespace stack
    1529             :      */
    1530          48 :     nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
    1531             :                             ident, NULL, NULL,
    1532             :                             NULL);
    1533             : 
    1534          48 :     if (nse != NULL)
    1535             :     {
    1536          44 :         switch (nse->itemtype)
    1537             :         {
    1538          38 :             case PLPGSQL_NSTYPE_VAR:
    1539          38 :                 return ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
    1540           6 :             case PLPGSQL_NSTYPE_REC:
    1541           6 :                 return ((PLpgSQL_rec *) (plpgsql_Datums[nse->itemno]))->datatype;
    1542           0 :             default:
    1543           0 :                 break;
    1544             :         }
    1545             :     }
    1546             : 
    1547             :     /* No match, complain */
    1548           4 :     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          36 : plpgsql_parse_cwordtype(List *idents)
    1565             : {
    1566          36 :     PLpgSQL_type *dtype = NULL;
    1567             :     PLpgSQL_nsitem *nse;
    1568             :     int         nnames;
    1569          36 :     RangeVar   *relvar = NULL;
    1570          36 :     const char *fldname = NULL;
    1571             :     Oid         classOid;
    1572          36 :     HeapTuple   attrtup = NULL;
    1573          36 :     HeapTuple   typetup = NULL;
    1574             :     Form_pg_attribute attrStruct;
    1575             :     MemoryContext oldCxt;
    1576             : 
    1577             :     /* Avoid memory leaks in the long-term function context */
    1578          36 :     oldCxt = MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
    1579             : 
    1580          36 :     if (list_length(idents) == 2)
    1581             :     {
    1582             :         /*
    1583             :          * Do a lookup in the current namespace stack
    1584             :          */
    1585          24 :         nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
    1586          24 :                                 strVal(linitial(idents)),
    1587          24 :                                 strVal(lsecond(idents)),
    1588             :                                 NULL,
    1589             :                                 &nnames);
    1590             : 
    1591          24 :         if (nse != NULL && nse->itemtype == PLPGSQL_NSTYPE_VAR)
    1592             :         {
    1593             :             /* Block-qualified reference to scalar variable. */
    1594           2 :             dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
    1595           2 :             goto done;
    1596             :         }
    1597          22 :         else if (nse != NULL && nse->itemtype == PLPGSQL_NSTYPE_REC &&
    1598           2 :                  nnames == 2)
    1599             :         {
    1600             :             /* Block-qualified reference to record variable. */
    1601           2 :             dtype = ((PLpgSQL_rec *) (plpgsql_Datums[nse->itemno]))->datatype;
    1602           2 :             goto done;
    1603             :         }
    1604             : 
    1605             :         /*
    1606             :          * First word could also be a table name
    1607             :          */
    1608          20 :         relvar = makeRangeVar(NULL,
    1609          20 :                               strVal(linitial(idents)),
    1610             :                               -1);
    1611          20 :         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          12 :         rvnames = list_delete_last(list_copy(idents));
    1625          12 :         relvar = makeRangeVarFromNameList(rvnames);
    1626          12 :         fldname = strVal(llast(idents));
    1627             :     }
    1628             : 
    1629             :     /* Look up relation name.  Can't lock it - we might not have privileges. */
    1630          32 :     classOid = RangeVarGetRelid(relvar, NoLock, false);
    1631             : 
    1632             :     /*
    1633             :      * Fetch the named table field and its type
    1634             :      */
    1635          26 :     attrtup = SearchSysCacheAttName(classOid, fldname);
    1636          26 :     if (!HeapTupleIsValid(attrtup))
    1637           2 :         ereport(ERROR,
    1638             :                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    1639             :                  errmsg("column \"%s\" of relation \"%s\" does not exist",
    1640             :                         fldname, relvar->relname)));
    1641          24 :     attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
    1642             : 
    1643          24 :     typetup = SearchSysCache1(TYPEOID,
    1644             :                               ObjectIdGetDatum(attrStruct->atttypid));
    1645          24 :     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          24 :     MemoryContextSwitchTo(oldCxt);
    1654          24 :     dtype = build_datatype(typetup,
    1655             :                            attrStruct->atttypmod,
    1656             :                            attrStruct->attcollation,
    1657             :                            NULL);
    1658          24 :     MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
    1659             : 
    1660          28 : done:
    1661          28 :     if (HeapTupleIsValid(attrtup))
    1662          24 :         ReleaseSysCache(attrtup);
    1663          28 :     if (HeapTupleIsValid(typetup))
    1664          24 :         ReleaseSysCache(typetup);
    1665             : 
    1666          28 :     MemoryContextSwitchTo(oldCxt);
    1667          28 :     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          60 : 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          60 :     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          60 :     classOid = RelnameGetRelid(ident);
    1694          60 :     if (!OidIsValid(classOid))
    1695           4 :         ereport(ERROR,
    1696             :                 (errcode(ERRCODE_UNDEFINED_TABLE),
    1697             :                  errmsg("relation \"%s\" does not exist", ident)));
    1698             : 
    1699             :     /* Some relkinds lack type OIDs */
    1700          56 :     typOid = get_rel_type_id(classOid);
    1701          56 :     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          56 :     typName = makeTypeName(ident);
    1708             : 
    1709          56 :     MemoryContextSwitchTo(oldCxt);
    1710             : 
    1711             :     /* Build and return the row type struct */
    1712          56 :     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          16 : 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          16 :     oldCxt = MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
    1736             : 
    1737             :     /* Look up relation name.  Can't lock it - we might not have privileges. */
    1738          16 :     relvar = makeRangeVarFromNameList(idents);
    1739          16 :     classOid = RangeVarGetRelid(relvar, NoLock, false);
    1740             : 
    1741             :     /* Some relkinds lack type OIDs */
    1742          10 :     typOid = get_rel_type_id(classOid);
    1743          10 :     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          10 :     typName = makeTypeNameFromNameList(idents);
    1750             : 
    1751          10 :     MemoryContextSwitchTo(oldCxt);
    1752             : 
    1753             :     /* Build and return the row type struct */
    1754          10 :     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       61984 : plpgsql_build_variable(const char *refname, int lineno, PLpgSQL_type *dtype,
    1768             :                        bool add2namespace)
    1769             : {
    1770             :     PLpgSQL_variable *result;
    1771             : 
    1772       61984 :     switch (dtype->ttype)
    1773             :     {
    1774       60494 :         case PLPGSQL_TTYPE_SCALAR:
    1775             :             {
    1776             :                 /* Ordinary scalar datatype */
    1777             :                 PLpgSQL_var *var;
    1778             : 
    1779       60494 :                 var = palloc0_object(PLpgSQL_var);
    1780       60494 :                 var->dtype = PLPGSQL_DTYPE_VAR;
    1781       60494 :                 var->refname = pstrdup(refname);
    1782       60494 :                 var->lineno = lineno;
    1783       60494 :                 var->datatype = dtype;
    1784             :                 /* other fields are left as 0, might be changed by caller */
    1785             : 
    1786             :                 /* preset to NULL */
    1787       60494 :                 var->value = 0;
    1788       60494 :                 var->isnull = true;
    1789       60494 :                 var->freeval = false;
    1790             : 
    1791       60494 :                 plpgsql_adddatum((PLpgSQL_datum *) var);
    1792       60494 :                 if (add2namespace)
    1793       55594 :                     plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR,
    1794             :                                        var->dno,
    1795             :                                        refname);
    1796       60494 :                 result = (PLpgSQL_variable *) var;
    1797       60494 :                 break;
    1798             :             }
    1799        1486 :         case PLPGSQL_TTYPE_REC:
    1800             :             {
    1801             :                 /* Composite type -- build a record variable */
    1802             :                 PLpgSQL_rec *rec;
    1803             : 
    1804        1486 :                 rec = plpgsql_build_record(refname, lineno,
    1805             :                                            dtype, dtype->typoid,
    1806             :                                            add2namespace);
    1807        1486 :                 result = (PLpgSQL_variable *) rec;
    1808        1486 :                 break;
    1809             :             }
    1810           4 :         case PLPGSQL_TTYPE_PSEUDO:
    1811           4 :             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       61980 :     return result;
    1824             : }
    1825             : 
    1826             : /*
    1827             :  * Build empty named record variable, and optionally add it to namespace
    1828             :  */
    1829             : PLpgSQL_rec *
    1830        9192 : plpgsql_build_record(const char *refname, int lineno,
    1831             :                      PLpgSQL_type *dtype, Oid rectypeid,
    1832             :                      bool add2namespace)
    1833             : {
    1834             :     PLpgSQL_rec *rec;
    1835             : 
    1836        9192 :     rec = palloc0_object(PLpgSQL_rec);
    1837        9192 :     rec->dtype = PLPGSQL_DTYPE_REC;
    1838        9192 :     rec->refname = pstrdup(refname);
    1839        9192 :     rec->lineno = lineno;
    1840             :     /* other fields are left as 0, might be changed by caller */
    1841        9192 :     rec->datatype = dtype;
    1842        9192 :     rec->rectypeid = rectypeid;
    1843        9192 :     rec->firstfield = -1;
    1844        9192 :     rec->erh = NULL;
    1845        9192 :     plpgsql_adddatum((PLpgSQL_datum *) rec);
    1846        9192 :     if (add2namespace)
    1847        9110 :         plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->dno, rec->refname);
    1848             : 
    1849        9192 :     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         192 : build_row_from_vars(PLpgSQL_variable **vars, int numvars)
    1858             : {
    1859             :     PLpgSQL_row *row;
    1860             :     int         i;
    1861             : 
    1862         192 :     row = palloc0_object(PLpgSQL_row);
    1863         192 :     row->dtype = PLPGSQL_DTYPE_ROW;
    1864         192 :     row->refname = "(unnamed row)";
    1865         192 :     row->lineno = -1;
    1866         192 :     row->rowtupdesc = CreateTemplateTupleDesc(numvars);
    1867         192 :     row->nfields = numvars;
    1868         192 :     row->fieldnames = palloc_array(char *, numvars);
    1869         192 :     row->varnos = palloc_array(int, numvars);
    1870             : 
    1871         616 :     for (i = 0; i < numvars; i++)
    1872             :     {
    1873         424 :         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         424 :         switch (var->dtype)
    1882             :         {
    1883         424 :             case PLPGSQL_DTYPE_VAR:
    1884             :             case PLPGSQL_DTYPE_PROMISE:
    1885         424 :                 typoid = ((PLpgSQL_var *) var)->datatype->typoid;
    1886         424 :                 typmod = ((PLpgSQL_var *) var)->datatype->atttypmod;
    1887         424 :                 typcoll = ((PLpgSQL_var *) var)->datatype->collation;
    1888         424 :                 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         424 :         row->fieldnames[i] = var->refname;
    1906         424 :         row->varnos[i] = var->dno;
    1907             : 
    1908         424 :         TupleDescInitEntry(row->rowtupdesc, i + 1,
    1909         424 :                            var->refname,
    1910             :                            typoid, typmod,
    1911             :                            0);
    1912         424 :         TupleDescInitEntryCollation(row->rowtupdesc, i + 1, typcoll);
    1913             :     }
    1914             : 
    1915         192 :     return row;
    1916             : }
    1917             : 
    1918             : /*
    1919             :  * Build a RECFIELD datum for the named field of the specified record variable
    1920             :  *
    1921             :  * If there's already such a datum, just return it; we don't need duplicates.
    1922             :  */
    1923             : PLpgSQL_recfield *
    1924        7442 : plpgsql_build_recfield(PLpgSQL_rec *rec, const char *fldname)
    1925             : {
    1926             :     PLpgSQL_recfield *recfield;
    1927             :     int         i;
    1928             : 
    1929             :     /* search for an existing datum referencing this field */
    1930        7442 :     i = rec->firstfield;
    1931       12070 :     while (i >= 0)
    1932             :     {
    1933        7766 :         PLpgSQL_recfield *fld = (PLpgSQL_recfield *) plpgsql_Datums[i];
    1934             : 
    1935             :         Assert(fld->dtype == PLPGSQL_DTYPE_RECFIELD &&
    1936             :                fld->recparentno == rec->dno);
    1937        7766 :         if (strcmp(fld->fieldname, fldname) == 0)
    1938        3138 :             return fld;
    1939        4628 :         i = fld->nextfield;
    1940             :     }
    1941             : 
    1942             :     /* nope, so make a new one */
    1943        4304 :     recfield = palloc0_object(PLpgSQL_recfield);
    1944        4304 :     recfield->dtype = PLPGSQL_DTYPE_RECFIELD;
    1945        4304 :     recfield->fieldname = pstrdup(fldname);
    1946        4304 :     recfield->recparentno = rec->dno;
    1947        4304 :     recfield->rectupledescid = INVALID_TUPLEDESC_IDENTIFIER;
    1948             : 
    1949        4304 :     plpgsql_adddatum((PLpgSQL_datum *) recfield);
    1950             : 
    1951             :     /* now we can link it into the parent's chain */
    1952        4304 :     recfield->nextfield = rec->firstfield;
    1953        4304 :     rec->firstfield = recfield->dno;
    1954             : 
    1955        4304 :     return recfield;
    1956             : }
    1957             : 
    1958             : /*
    1959             :  * plpgsql_build_datatype
    1960             :  *      Build PLpgSQL_type struct given type OID, typmod, collation,
    1961             :  *      and type's parsed name.
    1962             :  *
    1963             :  * If collation is not InvalidOid then it overrides the type's default
    1964             :  * collation.  But collation is ignored if the datatype is non-collatable.
    1965             :  *
    1966             :  * origtypname is the parsed form of what the user wrote as the type name.
    1967             :  * It can be NULL if the type could not be a composite type, or if it was
    1968             :  * identified by OID to begin with (e.g., it's a function argument type).
    1969             :  * origtypname is in short-lived storage and must be copied if we choose
    1970             :  * to incorporate it into the function's parse tree.
    1971             :  */
    1972             : PLpgSQL_type *
    1973       61848 : plpgsql_build_datatype(Oid typeOid, int32 typmod,
    1974             :                        Oid collation, TypeName *origtypname)
    1975             : {
    1976             :     HeapTuple   typeTup;
    1977             :     PLpgSQL_type *typ;
    1978             : 
    1979       61848 :     typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
    1980       61848 :     if (!HeapTupleIsValid(typeTup))
    1981           0 :         elog(ERROR, "cache lookup failed for type %u", typeOid);
    1982             : 
    1983       61848 :     typ = build_datatype(typeTup, typmod, collation, origtypname);
    1984             : 
    1985       61848 :     ReleaseSysCache(typeTup);
    1986             : 
    1987       61848 :     return typ;
    1988             : }
    1989             : 
    1990             : /*
    1991             :  * Utility subroutine to make a PLpgSQL_type struct given a pg_type entry
    1992             :  * and additional details (see comments for plpgsql_build_datatype).
    1993             :  */
    1994             : static PLpgSQL_type *
    1995       62016 : build_datatype(HeapTuple typeTup, int32 typmod,
    1996             :                Oid collation, TypeName *origtypname)
    1997             : {
    1998       62016 :     Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
    1999             :     PLpgSQL_type *typ;
    2000             : 
    2001       62016 :     if (!typeStruct->typisdefined)
    2002           0 :         ereport(ERROR,
    2003             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2004             :                  errmsg("type \"%s\" is only a shell",
    2005             :                         NameStr(typeStruct->typname))));
    2006             : 
    2007       62016 :     typ = palloc_object(PLpgSQL_type);
    2008             : 
    2009       62016 :     typ->typname = pstrdup(NameStr(typeStruct->typname));
    2010       62016 :     typ->typoid = typeStruct->oid;
    2011       62016 :     switch (typeStruct->typtype)
    2012             :     {
    2013       60384 :         case TYPTYPE_BASE:
    2014             :         case TYPTYPE_ENUM:
    2015             :         case TYPTYPE_RANGE:
    2016             :         case TYPTYPE_MULTIRANGE:
    2017       60384 :             typ->ttype = PLPGSQL_TTYPE_SCALAR;
    2018       60384 :             break;
    2019         256 :         case TYPTYPE_COMPOSITE:
    2020         256 :             typ->ttype = PLPGSQL_TTYPE_REC;
    2021         256 :             break;
    2022         174 :         case TYPTYPE_DOMAIN:
    2023         174 :             if (type_is_rowtype(typeStruct->typbasetype))
    2024          36 :                 typ->ttype = PLPGSQL_TTYPE_REC;
    2025             :             else
    2026         138 :                 typ->ttype = PLPGSQL_TTYPE_SCALAR;
    2027         174 :             break;
    2028        1202 :         case TYPTYPE_PSEUDO:
    2029        1202 :             if (typ->typoid == RECORDOID)
    2030        1192 :                 typ->ttype = PLPGSQL_TTYPE_REC;
    2031             :             else
    2032          10 :                 typ->ttype = PLPGSQL_TTYPE_PSEUDO;
    2033        1202 :             break;
    2034           0 :         default:
    2035           0 :             elog(ERROR, "unrecognized typtype: %d",
    2036             :                  (int) typeStruct->typtype);
    2037             :             break;
    2038             :     }
    2039       62016 :     typ->typlen = typeStruct->typlen;
    2040       62016 :     typ->typbyval = typeStruct->typbyval;
    2041       62016 :     typ->typtype = typeStruct->typtype;
    2042       62016 :     typ->collation = typeStruct->typcollation;
    2043       62016 :     if (OidIsValid(collation) && OidIsValid(typ->collation))
    2044        1598 :         typ->collation = collation;
    2045             :     /* Detect if type is true array, or domain thereof */
    2046             :     /* NB: this is only used to decide whether to apply expand_array */
    2047       62016 :     if (typeStruct->typtype == TYPTYPE_BASE)
    2048             :     {
    2049             :         /*
    2050             :          * This test should include what get_element_type() checks.  We also
    2051             :          * disallow non-toastable array types (i.e. oidvector and int2vector).
    2052             :          */
    2053       64768 :         typ->typisarray = (IsTrueArrayType(typeStruct) &&
    2054        4468 :                            typeStruct->typstorage != TYPSTORAGE_PLAIN);
    2055             :     }
    2056        1716 :     else if (typeStruct->typtype == TYPTYPE_DOMAIN)
    2057             :     {
    2058             :         /* we can short-circuit looking up base types if it's not varlena */
    2059         444 :         typ->typisarray = (typeStruct->typlen == -1 &&
    2060         270 :                            typeStruct->typstorage != TYPSTORAGE_PLAIN &&
    2061          96 :                            OidIsValid(get_base_element_type(typeStruct->typbasetype)));
    2062             :     }
    2063             :     else
    2064        1542 :         typ->typisarray = false;
    2065       62016 :     typ->atttypmod = typmod;
    2066             : 
    2067             :     /*
    2068             :      * If it's a named composite type (or domain over one), find the typcache
    2069             :      * entry and record the current tupdesc ID, so we can detect changes
    2070             :      * (including drops).  We don't currently support on-the-fly replacement
    2071             :      * of non-composite types, else we might want to do this for them too.
    2072             :      */
    2073       62016 :     if (typ->ttype == PLPGSQL_TTYPE_REC && typ->typoid != RECORDOID)
    2074         292 :     {
    2075             :         TypeCacheEntry *typentry;
    2076             : 
    2077         292 :         typentry = lookup_type_cache(typ->typoid,
    2078             :                                      TYPECACHE_TUPDESC |
    2079             :                                      TYPECACHE_DOMAIN_BASE_INFO);
    2080         292 :         if (typentry->typtype == TYPTYPE_DOMAIN)
    2081          36 :             typentry = lookup_type_cache(typentry->domainBaseType,
    2082             :                                          TYPECACHE_TUPDESC);
    2083         292 :         if (typentry->tupDesc == NULL)
    2084           0 :             ereport(ERROR,
    2085             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    2086             :                      errmsg("type %s is not composite",
    2087             :                             format_type_be(typ->typoid))));
    2088             : 
    2089         292 :         typ->origtypname = copyObject(origtypname);
    2090         292 :         typ->tcache = typentry;
    2091         292 :         typ->tupdesc_id = typentry->tupDesc_identifier;
    2092             :     }
    2093             :     else
    2094             :     {
    2095       61724 :         typ->origtypname = NULL;
    2096       61724 :         typ->tcache = NULL;
    2097       61724 :         typ->tupdesc_id = 0;
    2098             :     }
    2099             : 
    2100       62016 :     return typ;
    2101             : }
    2102             : 
    2103             : /*
    2104             :  * Build an array type for the element type specified as argument.
    2105             :  */
    2106             : PLpgSQL_type *
    2107          28 : plpgsql_build_datatype_arrayof(PLpgSQL_type *dtype)
    2108             : {
    2109             :     Oid         array_typeid;
    2110             : 
    2111             :     /*
    2112             :      * If it's already an array type, use it as-is: Postgres doesn't do nested
    2113             :      * arrays.
    2114             :      */
    2115          28 :     if (dtype->typisarray)
    2116           0 :         return dtype;
    2117             : 
    2118          28 :     array_typeid = get_array_type(dtype->typoid);
    2119          28 :     if (!OidIsValid(array_typeid))
    2120           2 :         ereport(ERROR,
    2121             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2122             :                  errmsg("could not find array type for data type %s",
    2123             :                         format_type_be(dtype->typoid))));
    2124             : 
    2125             :     /* Note we inherit typmod and collation, if any, from the element type */
    2126          26 :     return plpgsql_build_datatype(array_typeid, dtype->atttypmod,
    2127             :                                   dtype->collation, NULL);
    2128             : }
    2129             : 
    2130             : /*
    2131             :  *  plpgsql_recognize_err_condition
    2132             :  *      Check condition name and translate it to SQLSTATE.
    2133             :  *
    2134             :  * Note: there are some cases where the same condition name has multiple
    2135             :  * entries in the table.  We arbitrarily return the first match.
    2136             :  */
    2137             : int
    2138         736 : plpgsql_recognize_err_condition(const char *condname, bool allow_sqlstate)
    2139             : {
    2140             :     int         i;
    2141             : 
    2142         736 :     if (allow_sqlstate)
    2143             :     {
    2144         694 :         if (strlen(condname) == 5 &&
    2145          52 :             strspn(condname, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") == 5)
    2146          52 :             return MAKE_SQLSTATE(condname[0],
    2147             :                                  condname[1],
    2148             :                                  condname[2],
    2149             :                                  condname[3],
    2150             :                                  condname[4]);
    2151             :     }
    2152             : 
    2153       78732 :     for (i = 0; exception_label_map[i].label != NULL; i++)
    2154             :     {
    2155       78732 :         if (strcmp(condname, exception_label_map[i].label) == 0)
    2156         684 :             return exception_label_map[i].sqlerrstate;
    2157             :     }
    2158             : 
    2159           0 :     ereport(ERROR,
    2160             :             (errcode(ERRCODE_UNDEFINED_OBJECT),
    2161             :              errmsg("unrecognized exception condition \"%s\"",
    2162             :                     condname)));
    2163             :     return 0;                   /* keep compiler quiet */
    2164             : }
    2165             : 
    2166             : /*
    2167             :  * plpgsql_parse_err_condition
    2168             :  *      Generate PLpgSQL_condition entry(s) for an exception condition name
    2169             :  *
    2170             :  * This has to be able to return a list because there are some duplicate
    2171             :  * names in the table of error code names.
    2172             :  */
    2173             : PLpgSQL_condition *
    2174         458 : plpgsql_parse_err_condition(char *condname)
    2175             : {
    2176             :     int         i;
    2177             :     PLpgSQL_condition *new;
    2178             :     PLpgSQL_condition *prev;
    2179             : 
    2180             :     /*
    2181             :      * XXX Eventually we will want to look for user-defined exception names
    2182             :      * here.
    2183             :      */
    2184             : 
    2185         458 :     if (strcmp(condname, "others") == 0)
    2186             :     {
    2187         164 :         new = palloc_object(PLpgSQL_condition);
    2188         164 :         new->sqlerrstate = PLPGSQL_OTHERS;
    2189         164 :         new->condname = condname;
    2190         164 :         new->next = NULL;
    2191         164 :         return new;
    2192             :     }
    2193             : 
    2194         294 :     prev = NULL;
    2195       74088 :     for (i = 0; exception_label_map[i].label != NULL; i++)
    2196             :     {
    2197       73794 :         if (strcmp(condname, exception_label_map[i].label) == 0)
    2198             :         {
    2199         300 :             new = palloc_object(PLpgSQL_condition);
    2200         300 :             new->sqlerrstate = exception_label_map[i].sqlerrstate;
    2201         300 :             new->condname = condname;
    2202         300 :             new->next = prev;
    2203         300 :             prev = new;
    2204             :         }
    2205             :     }
    2206             : 
    2207         294 :     if (!prev)
    2208           0 :         ereport(ERROR,
    2209             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2210             :                  errmsg("unrecognized exception condition \"%s\"",
    2211             :                         condname)));
    2212             : 
    2213         294 :     return prev;
    2214             : }
    2215             : 
    2216             : /* ----------
    2217             :  * plpgsql_start_datums         Initialize datum list at compile startup.
    2218             :  * ----------
    2219             :  */
    2220             : static void
    2221        9796 : plpgsql_start_datums(void)
    2222             : {
    2223        9796 :     datums_alloc = 128;
    2224        9796 :     plpgsql_nDatums = 0;
    2225             :     /* This is short-lived, so needn't allocate in function's cxt */
    2226        9796 :     plpgsql_Datums = MemoryContextAlloc(plpgsql_compile_tmp_cxt,
    2227             :                                         sizeof(PLpgSQL_datum *) * datums_alloc);
    2228             :     /* datums_last tracks what's been seen by plpgsql_add_initdatums() */
    2229        9796 :     datums_last = 0;
    2230        9796 : }
    2231             : 
    2232             : /* ----------
    2233             :  * plpgsql_adddatum         Add a variable, record or row
    2234             :  *                  to the compiler's datum list.
    2235             :  * ----------
    2236             :  */
    2237             : void
    2238       75630 : plpgsql_adddatum(PLpgSQL_datum *newdatum)
    2239             : {
    2240       75630 :     if (plpgsql_nDatums == datums_alloc)
    2241             :     {
    2242           0 :         datums_alloc *= 2;
    2243           0 :         plpgsql_Datums = repalloc(plpgsql_Datums, sizeof(PLpgSQL_datum *) * datums_alloc);
    2244             :     }
    2245             : 
    2246       75630 :     newdatum->dno = plpgsql_nDatums;
    2247       75630 :     plpgsql_Datums[plpgsql_nDatums++] = newdatum;
    2248       75630 : }
    2249             : 
    2250             : /* ----------
    2251             :  * plpgsql_finish_datums    Copy completed datum info into function struct.
    2252             :  * ----------
    2253             :  */
    2254             : static void
    2255        9618 : plpgsql_finish_datums(PLpgSQL_function *function)
    2256             : {
    2257        9618 :     Size        copiable_size = 0;
    2258             :     int         i;
    2259             : 
    2260        9618 :     function->ndatums = plpgsql_nDatums;
    2261        9618 :     function->datums = palloc_array(PLpgSQL_datum *, plpgsql_nDatums);
    2262       84894 :     for (i = 0; i < plpgsql_nDatums; i++)
    2263             :     {
    2264       75276 :         function->datums[i] = plpgsql_Datums[i];
    2265             : 
    2266             :         /* This must agree with copy_plpgsql_datums on what is copiable */
    2267       75276 :         switch (function->datums[i]->dtype)
    2268             :         {
    2269       60194 :             case PLPGSQL_DTYPE_VAR:
    2270             :             case PLPGSQL_DTYPE_PROMISE:
    2271       60194 :                 copiable_size += MAXALIGN(sizeof(PLpgSQL_var));
    2272       60194 :                 break;
    2273        9166 :             case PLPGSQL_DTYPE_REC:
    2274        9166 :                 copiable_size += MAXALIGN(sizeof(PLpgSQL_rec));
    2275        9166 :                 break;
    2276        5916 :             default:
    2277        5916 :                 break;
    2278             :         }
    2279             :     }
    2280        9618 :     function->copiable_size = copiable_size;
    2281        9618 : }
    2282             : 
    2283             : 
    2284             : /* ----------
    2285             :  * plpgsql_add_initdatums       Make an array of the datum numbers of
    2286             :  *                  all the initializable datums created since the last call
    2287             :  *                  to this function.
    2288             :  *
    2289             :  * If varnos is NULL, we just forget any datum entries created since the
    2290             :  * last call.
    2291             :  *
    2292             :  * This is used around a DECLARE section to create a list of the datums
    2293             :  * that have to be initialized at block entry.  Note that datums can also
    2294             :  * be created elsewhere than DECLARE, eg by a FOR-loop, but it is then
    2295             :  * the responsibility of special-purpose code to initialize them.
    2296             :  * ----------
    2297             :  */
    2298             : int
    2299        7336 : plpgsql_add_initdatums(int **varnos)
    2300             : {
    2301             :     int         i;
    2302        7336 :     int         n = 0;
    2303             : 
    2304             :     /*
    2305             :      * The set of dtypes recognized here must match what exec_stmt_block()
    2306             :      * cares about (re)initializing at block entry.
    2307             :      */
    2308       30422 :     for (i = datums_last; i < plpgsql_nDatums; i++)
    2309             :     {
    2310       23086 :         switch (plpgsql_Datums[i]->dtype)
    2311             :         {
    2312       14462 :             case PLPGSQL_DTYPE_VAR:
    2313             :             case PLPGSQL_DTYPE_REC:
    2314       14462 :                 n++;
    2315       14462 :                 break;
    2316             : 
    2317        8624 :             default:
    2318        8624 :                 break;
    2319             :         }
    2320             :     }
    2321             : 
    2322        7336 :     if (varnos != NULL)
    2323             :     {
    2324        3642 :         if (n > 0)
    2325             :         {
    2326        3642 :             *varnos = palloc_array(int, n);
    2327             : 
    2328        3642 :             n = 0;
    2329        9888 :             for (i = datums_last; i < plpgsql_nDatums; i++)
    2330             :             {
    2331        6246 :                 switch (plpgsql_Datums[i]->dtype)
    2332             :                 {
    2333        6174 :                     case PLPGSQL_DTYPE_VAR:
    2334             :                     case PLPGSQL_DTYPE_REC:
    2335        6174 :                         (*varnos)[n++] = plpgsql_Datums[i]->dno;
    2336             : 
    2337        6246 :                     default:
    2338        6246 :                         break;
    2339             :                 }
    2340             :             }
    2341             :         }
    2342             :         else
    2343           0 :             *varnos = NULL;
    2344             :     }
    2345             : 
    2346        7336 :     datums_last = plpgsql_nDatums;
    2347        7336 :     return n;
    2348             : }

Generated by: LCOV version 1.16