LCOV - code coverage report
Current view: top level - src/pl/plpgsql/src - pl_exec.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 2321 2525 91.9 %
Date: 2019-09-22 07:07:17 Functions: 93 93 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pl_exec.c        - Executor for the PL/pgSQL
       4             :  *            procedural language
       5             :  *
       6             :  * Portions Copyright (c) 1996-2019, 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_exec.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : 
      16             : #include "postgres.h"
      17             : 
      18             : #include <ctype.h>
      19             : 
      20             : #include "access/detoast.h"
      21             : #include "access/htup_details.h"
      22             : #include "access/transam.h"
      23             : #include "access/tupconvert.h"
      24             : #include "catalog/pg_proc.h"
      25             : #include "catalog/pg_type.h"
      26             : #include "commands/defrem.h"
      27             : #include "executor/execExpr.h"
      28             : #include "executor/spi.h"
      29             : #include "executor/spi_priv.h"
      30             : #include "funcapi.h"
      31             : #include "miscadmin.h"
      32             : #include "nodes/nodeFuncs.h"
      33             : #include "optimizer/optimizer.h"
      34             : #include "parser/parse_coerce.h"
      35             : #include "parser/parse_type.h"
      36             : #include "parser/scansup.h"
      37             : #include "storage/proc.h"
      38             : #include "tcop/tcopprot.h"
      39             : #include "tcop/utility.h"
      40             : #include "utils/array.h"
      41             : #include "utils/builtins.h"
      42             : #include "utils/datum.h"
      43             : #include "utils/fmgroids.h"
      44             : #include "utils/lsyscache.h"
      45             : #include "utils/memutils.h"
      46             : #include "utils/rel.h"
      47             : #include "utils/snapmgr.h"
      48             : #include "utils/syscache.h"
      49             : #include "utils/typcache.h"
      50             : 
      51             : #include "plpgsql.h"
      52             : 
      53             : 
      54             : typedef struct
      55             : {
      56             :     int         nargs;          /* number of arguments */
      57             :     Oid        *types;          /* types of arguments */
      58             :     Datum      *values;         /* evaluated argument values */
      59             :     char       *nulls;          /* null markers (' '/'n' style) */
      60             : } PreparedParamsData;
      61             : 
      62             : /*
      63             :  * All plpgsql function executions within a single transaction share the same
      64             :  * executor EState for evaluating "simple" expressions.  Each function call
      65             :  * creates its own "eval_econtext" ExprContext within this estate for
      66             :  * per-evaluation workspace.  eval_econtext is freed at normal function exit,
      67             :  * and the EState is freed at transaction end (in case of error, we assume
      68             :  * that the abort mechanisms clean it all up).  Furthermore, any exception
      69             :  * block within a function has to have its own eval_econtext separate from
      70             :  * the containing function's, so that we can clean up ExprContext callbacks
      71             :  * properly at subtransaction exit.  We maintain a stack that tracks the
      72             :  * individual econtexts so that we can clean up correctly at subxact exit.
      73             :  *
      74             :  * This arrangement is a bit tedious to maintain, but it's worth the trouble
      75             :  * so that we don't have to re-prepare simple expressions on each trip through
      76             :  * a function.  (We assume the case to optimize is many repetitions of a
      77             :  * function within a transaction.)
      78             :  *
      79             :  * However, there's no value in trying to amortize simple expression setup
      80             :  * across multiple executions of a DO block (inline code block), since there
      81             :  * can never be any.  If we use the shared EState for a DO block, the expr
      82             :  * state trees are effectively leaked till end of transaction, and that can
      83             :  * add up if the user keeps on submitting DO blocks.  Therefore, each DO block
      84             :  * has its own simple-expression EState, which is cleaned up at exit from
      85             :  * plpgsql_inline_handler().  DO blocks still use the simple_econtext_stack,
      86             :  * though, so that subxact abort cleanup does the right thing.
      87             :  */
      88             : typedef struct SimpleEcontextStackEntry
      89             : {
      90             :     ExprContext *stack_econtext;    /* a stacked econtext */
      91             :     SubTransactionId xact_subxid;   /* ID for current subxact */
      92             :     struct SimpleEcontextStackEntry *next;  /* next stack entry up */
      93             : } SimpleEcontextStackEntry;
      94             : 
      95             : static EState *shared_simple_eval_estate = NULL;
      96             : static SimpleEcontextStackEntry *simple_econtext_stack = NULL;
      97             : 
      98             : /*
      99             :  * Memory management within a plpgsql function generally works with three
     100             :  * contexts:
     101             :  *
     102             :  * 1. Function-call-lifespan data, such as variable values, is kept in the
     103             :  * "main" context, a/k/a the "SPI Proc" context established by SPI_connect().
     104             :  * This is usually the CurrentMemoryContext while running code in this module
     105             :  * (which is not good, because careless coding can easily cause
     106             :  * function-lifespan memory leaks, but we live with it for now).
     107             :  *
     108             :  * 2. Some statement-execution routines need statement-lifespan workspace.
     109             :  * A suitable context is created on-demand by get_stmt_mcontext(), and must
     110             :  * be reset at the end of the requesting routine.  Error recovery will clean
     111             :  * it up automatically.  Nested statements requiring statement-lifespan
     112             :  * workspace will result in a stack of such contexts, see push_stmt_mcontext().
     113             :  *
     114             :  * 3. We use the eval_econtext's per-tuple memory context for expression
     115             :  * evaluation, and as a general-purpose workspace for short-lived allocations.
     116             :  * Such allocations usually aren't explicitly freed, but are left to be
     117             :  * cleaned up by a context reset, typically done by exec_eval_cleanup().
     118             :  *
     119             :  * These macros are for use in making short-lived allocations:
     120             :  */
     121             : #define get_eval_mcontext(estate) \
     122             :     ((estate)->eval_econtext->ecxt_per_tuple_memory)
     123             : #define eval_mcontext_alloc(estate, sz) \
     124             :     MemoryContextAlloc(get_eval_mcontext(estate), sz)
     125             : #define eval_mcontext_alloc0(estate, sz) \
     126             :     MemoryContextAllocZero(get_eval_mcontext(estate), sz)
     127             : 
     128             : /*
     129             :  * We use a session-wide hash table for caching cast information.
     130             :  *
     131             :  * Once built, the compiled expression trees (cast_expr fields) survive for
     132             :  * the life of the session.  At some point it might be worth invalidating
     133             :  * those after pg_cast changes, but for the moment we don't bother.
     134             :  *
     135             :  * The evaluation state trees (cast_exprstate) are managed in the same way as
     136             :  * simple expressions (i.e., we assume cast expressions are always simple).
     137             :  *
     138             :  * As with simple expressions, DO blocks don't use the shared hash table but
     139             :  * must have their own.  This isn't ideal, but we don't want to deal with
     140             :  * multiple simple_eval_estates within a DO block.
     141             :  */
     142             : typedef struct                  /* lookup key for cast info */
     143             : {
     144             :     /* NB: we assume this struct contains no padding bytes */
     145             :     Oid         srctype;        /* source type for cast */
     146             :     Oid         dsttype;        /* destination type for cast */
     147             :     int32       srctypmod;      /* source typmod for cast */
     148             :     int32       dsttypmod;      /* destination typmod for cast */
     149             : } plpgsql_CastHashKey;
     150             : 
     151             : typedef struct                  /* cast_hash table entry */
     152             : {
     153             :     plpgsql_CastHashKey key;    /* hash key --- MUST BE FIRST */
     154             :     Expr       *cast_expr;      /* cast expression, or NULL if no-op cast */
     155             :     CachedExpression *cast_cexpr;   /* cached expression backing the above */
     156             :     /* ExprState is valid only when cast_lxid matches current LXID */
     157             :     ExprState  *cast_exprstate; /* expression's eval tree */
     158             :     bool        cast_in_use;    /* true while we're executing eval tree */
     159             :     LocalTransactionId cast_lxid;
     160             : } plpgsql_CastHashEntry;
     161             : 
     162             : static MemoryContext shared_cast_context = NULL;
     163             : static HTAB *shared_cast_hash = NULL;
     164             : 
     165             : /*
     166             :  * LOOP_RC_PROCESSING encapsulates common logic for looping statements to
     167             :  * handle return/exit/continue result codes from the loop body statement(s).
     168             :  * It's meant to be used like this:
     169             :  *
     170             :  *      int rc = PLPGSQL_RC_OK;
     171             :  *      for (...)
     172             :  *      {
     173             :  *          ...
     174             :  *          rc = exec_stmts(estate, stmt->body);
     175             :  *          LOOP_RC_PROCESSING(stmt->label, break);
     176             :  *          ...
     177             :  *      }
     178             :  *      return rc;
     179             :  *
     180             :  * If execution of the loop should terminate, LOOP_RC_PROCESSING will execute
     181             :  * "exit_action" (typically a "break" or "goto"), after updating "rc" to the
     182             :  * value the current statement should return.  If execution should continue,
     183             :  * LOOP_RC_PROCESSING will do nothing except reset "rc" to PLPGSQL_RC_OK.
     184             :  *
     185             :  * estate and rc are implicit arguments to the macro.
     186             :  * estate->exitlabel is examined and possibly updated.
     187             :  */
     188             : #define LOOP_RC_PROCESSING(looplabel, exit_action) \
     189             :     if (rc == PLPGSQL_RC_RETURN) \
     190             :     { \
     191             :         /* RETURN, so propagate RC_RETURN out */ \
     192             :         exit_action; \
     193             :     } \
     194             :     else if (rc == PLPGSQL_RC_EXIT) \
     195             :     { \
     196             :         if (estate->exitlabel == NULL) \
     197             :         { \
     198             :             /* unlabelled EXIT terminates this loop */ \
     199             :             rc = PLPGSQL_RC_OK; \
     200             :             exit_action; \
     201             :         } \
     202             :         else if ((looplabel) != NULL && \
     203             :                  strcmp(looplabel, estate->exitlabel) == 0) \
     204             :         { \
     205             :             /* labelled EXIT matching this loop, so terminate loop */ \
     206             :             estate->exitlabel = NULL; \
     207             :             rc = PLPGSQL_RC_OK; \
     208             :             exit_action; \
     209             :         } \
     210             :         else \
     211             :         { \
     212             :             /* non-matching labelled EXIT, propagate RC_EXIT out */ \
     213             :             exit_action; \
     214             :         } \
     215             :     } \
     216             :     else if (rc == PLPGSQL_RC_CONTINUE) \
     217             :     { \
     218             :         if (estate->exitlabel == NULL) \
     219             :         { \
     220             :             /* unlabelled CONTINUE matches this loop, so continue in loop */ \
     221             :             rc = PLPGSQL_RC_OK; \
     222             :         } \
     223             :         else if ((looplabel) != NULL && \
     224             :                  strcmp(looplabel, estate->exitlabel) == 0) \
     225             :         { \
     226             :             /* labelled CONTINUE matching this loop, so continue in loop */ \
     227             :             estate->exitlabel = NULL; \
     228             :             rc = PLPGSQL_RC_OK; \
     229             :         } \
     230             :         else \
     231             :         { \
     232             :             /* non-matching labelled CONTINUE, propagate RC_CONTINUE out */ \
     233             :             exit_action; \
     234             :         } \
     235             :     } \
     236             :     else \
     237             :         Assert(rc == PLPGSQL_RC_OK)
     238             : 
     239             : /************************************************************
     240             :  * Local function forward declarations
     241             :  ************************************************************/
     242             : static void coerce_function_result_tuple(PLpgSQL_execstate *estate,
     243             :                                          TupleDesc tupdesc);
     244             : static void plpgsql_exec_error_callback(void *arg);
     245             : static void copy_plpgsql_datums(PLpgSQL_execstate *estate,
     246             :                                 PLpgSQL_function *func);
     247             : static void plpgsql_fulfill_promise(PLpgSQL_execstate *estate,
     248             :                                     PLpgSQL_var *var);
     249             : static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate);
     250             : static void push_stmt_mcontext(PLpgSQL_execstate *estate);
     251             : static void pop_stmt_mcontext(PLpgSQL_execstate *estate);
     252             : 
     253             : static int  exec_stmt_block(PLpgSQL_execstate *estate,
     254             :                             PLpgSQL_stmt_block *block);
     255             : static int  exec_stmts(PLpgSQL_execstate *estate,
     256             :                        List *stmts);
     257             : static int  exec_stmt(PLpgSQL_execstate *estate,
     258             :                       PLpgSQL_stmt *stmt);
     259             : static int  exec_stmt_assign(PLpgSQL_execstate *estate,
     260             :                              PLpgSQL_stmt_assign *stmt);
     261             : static int  exec_stmt_perform(PLpgSQL_execstate *estate,
     262             :                               PLpgSQL_stmt_perform *stmt);
     263             : static int  exec_stmt_call(PLpgSQL_execstate *estate,
     264             :                            PLpgSQL_stmt_call *stmt);
     265             : static int  exec_stmt_getdiag(PLpgSQL_execstate *estate,
     266             :                               PLpgSQL_stmt_getdiag *stmt);
     267             : static int  exec_stmt_if(PLpgSQL_execstate *estate,
     268             :                          PLpgSQL_stmt_if *stmt);
     269             : static int  exec_stmt_case(PLpgSQL_execstate *estate,
     270             :                            PLpgSQL_stmt_case *stmt);
     271             : static int  exec_stmt_loop(PLpgSQL_execstate *estate,
     272             :                            PLpgSQL_stmt_loop *stmt);
     273             : static int  exec_stmt_while(PLpgSQL_execstate *estate,
     274             :                             PLpgSQL_stmt_while *stmt);
     275             : static int  exec_stmt_fori(PLpgSQL_execstate *estate,
     276             :                            PLpgSQL_stmt_fori *stmt);
     277             : static int  exec_stmt_fors(PLpgSQL_execstate *estate,
     278             :                            PLpgSQL_stmt_fors *stmt);
     279             : static int  exec_stmt_forc(PLpgSQL_execstate *estate,
     280             :                            PLpgSQL_stmt_forc *stmt);
     281             : static int  exec_stmt_foreach_a(PLpgSQL_execstate *estate,
     282             :                                 PLpgSQL_stmt_foreach_a *stmt);
     283             : static int  exec_stmt_open(PLpgSQL_execstate *estate,
     284             :                            PLpgSQL_stmt_open *stmt);
     285             : static int  exec_stmt_fetch(PLpgSQL_execstate *estate,
     286             :                             PLpgSQL_stmt_fetch *stmt);
     287             : static int  exec_stmt_close(PLpgSQL_execstate *estate,
     288             :                             PLpgSQL_stmt_close *stmt);
     289             : static int  exec_stmt_exit(PLpgSQL_execstate *estate,
     290             :                            PLpgSQL_stmt_exit *stmt);
     291             : static int  exec_stmt_return(PLpgSQL_execstate *estate,
     292             :                              PLpgSQL_stmt_return *stmt);
     293             : static int  exec_stmt_return_next(PLpgSQL_execstate *estate,
     294             :                                   PLpgSQL_stmt_return_next *stmt);
     295             : static int  exec_stmt_return_query(PLpgSQL_execstate *estate,
     296             :                                    PLpgSQL_stmt_return_query *stmt);
     297             : static int  exec_stmt_raise(PLpgSQL_execstate *estate,
     298             :                             PLpgSQL_stmt_raise *stmt);
     299             : static int  exec_stmt_assert(PLpgSQL_execstate *estate,
     300             :                              PLpgSQL_stmt_assert *stmt);
     301             : static int  exec_stmt_execsql(PLpgSQL_execstate *estate,
     302             :                               PLpgSQL_stmt_execsql *stmt);
     303             : static int  exec_stmt_dynexecute(PLpgSQL_execstate *estate,
     304             :                                  PLpgSQL_stmt_dynexecute *stmt);
     305             : static int  exec_stmt_dynfors(PLpgSQL_execstate *estate,
     306             :                               PLpgSQL_stmt_dynfors *stmt);
     307             : static int  exec_stmt_commit(PLpgSQL_execstate *estate,
     308             :                              PLpgSQL_stmt_commit *stmt);
     309             : static int  exec_stmt_rollback(PLpgSQL_execstate *estate,
     310             :                                PLpgSQL_stmt_rollback *stmt);
     311             : static int  exec_stmt_set(PLpgSQL_execstate *estate,
     312             :                           PLpgSQL_stmt_set *stmt);
     313             : 
     314             : static void plpgsql_estate_setup(PLpgSQL_execstate *estate,
     315             :                                  PLpgSQL_function *func,
     316             :                                  ReturnSetInfo *rsi,
     317             :                                  EState *simple_eval_estate);
     318             : static void exec_eval_cleanup(PLpgSQL_execstate *estate);
     319             : 
     320             : static void exec_prepare_plan(PLpgSQL_execstate *estate,
     321             :                               PLpgSQL_expr *expr, int cursorOptions,
     322             :                               bool keepplan);
     323             : static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr);
     324             : static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan);
     325             : static void exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno);
     326             : static bool contains_target_param(Node *node, int *target_dno);
     327             : static bool exec_eval_simple_expr(PLpgSQL_execstate *estate,
     328             :                                   PLpgSQL_expr *expr,
     329             :                                   Datum *result,
     330             :                                   bool *isNull,
     331             :                                   Oid *rettype,
     332             :                                   int32 *rettypmod);
     333             : 
     334             : static void exec_assign_expr(PLpgSQL_execstate *estate,
     335             :                              PLpgSQL_datum *target,
     336             :                              PLpgSQL_expr *expr);
     337             : static void exec_assign_c_string(PLpgSQL_execstate *estate,
     338             :                                  PLpgSQL_datum *target,
     339             :                                  const char *str);
     340             : static void exec_assign_value(PLpgSQL_execstate *estate,
     341             :                               PLpgSQL_datum *target,
     342             :                               Datum value, bool isNull,
     343             :                               Oid valtype, int32 valtypmod);
     344             : static void exec_eval_datum(PLpgSQL_execstate *estate,
     345             :                             PLpgSQL_datum *datum,
     346             :                             Oid *typeid,
     347             :                             int32 *typetypmod,
     348             :                             Datum *value,
     349             :                             bool *isnull);
     350             : static int  exec_eval_integer(PLpgSQL_execstate *estate,
     351             :                               PLpgSQL_expr *expr,
     352             :                               bool *isNull);
     353             : static bool exec_eval_boolean(PLpgSQL_execstate *estate,
     354             :                               PLpgSQL_expr *expr,
     355             :                               bool *isNull);
     356             : static Datum exec_eval_expr(PLpgSQL_execstate *estate,
     357             :                             PLpgSQL_expr *expr,
     358             :                             bool *isNull,
     359             :                             Oid *rettype,
     360             :                             int32 *rettypmod);
     361             : static int  exec_run_select(PLpgSQL_execstate *estate,
     362             :                             PLpgSQL_expr *expr, long maxtuples, Portal *portalP);
     363             : static int  exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
     364             :                            Portal portal, bool prefetch_ok);
     365             : static ParamListInfo setup_param_list(PLpgSQL_execstate *estate,
     366             :                                       PLpgSQL_expr *expr);
     367             : static ParamExternData *plpgsql_param_fetch(ParamListInfo params,
     368             :                                             int paramid, bool speculative,
     369             :                                             ParamExternData *workspace);
     370             : static void plpgsql_param_compile(ParamListInfo params, Param *param,
     371             :                                   ExprState *state,
     372             :                                   Datum *resv, bool *resnull);
     373             : static void plpgsql_param_eval_var(ExprState *state, ExprEvalStep *op,
     374             :                                    ExprContext *econtext);
     375             : static void plpgsql_param_eval_var_ro(ExprState *state, ExprEvalStep *op,
     376             :                                       ExprContext *econtext);
     377             : static void plpgsql_param_eval_recfield(ExprState *state, ExprEvalStep *op,
     378             :                                         ExprContext *econtext);
     379             : static void plpgsql_param_eval_generic(ExprState *state, ExprEvalStep *op,
     380             :                                        ExprContext *econtext);
     381             : static void plpgsql_param_eval_generic_ro(ExprState *state, ExprEvalStep *op,
     382             :                                           ExprContext *econtext);
     383             : static void exec_move_row(PLpgSQL_execstate *estate,
     384             :                           PLpgSQL_variable *target,
     385             :                           HeapTuple tup, TupleDesc tupdesc);
     386             : static void revalidate_rectypeid(PLpgSQL_rec *rec);
     387             : static ExpandedRecordHeader *make_expanded_record_for_rec(PLpgSQL_execstate *estate,
     388             :                                                           PLpgSQL_rec *rec,
     389             :                                                           TupleDesc srctupdesc,
     390             :                                                           ExpandedRecordHeader *srcerh);
     391             : static void exec_move_row_from_fields(PLpgSQL_execstate *estate,
     392             :                                       PLpgSQL_variable *target,
     393             :                                       ExpandedRecordHeader *newerh,
     394             :                                       Datum *values, bool *nulls,
     395             :                                       TupleDesc tupdesc);
     396             : static bool compatible_tupdescs(TupleDesc src_tupdesc, TupleDesc dst_tupdesc);
     397             : static HeapTuple make_tuple_from_row(PLpgSQL_execstate *estate,
     398             :                                      PLpgSQL_row *row,
     399             :                                      TupleDesc tupdesc);
     400             : static TupleDesc deconstruct_composite_datum(Datum value,
     401             :                                              HeapTupleData *tmptup);
     402             : static void exec_move_row_from_datum(PLpgSQL_execstate *estate,
     403             :                                      PLpgSQL_variable *target,
     404             :                                      Datum value);
     405             : static void instantiate_empty_record_variable(PLpgSQL_execstate *estate,
     406             :                                               PLpgSQL_rec *rec);
     407             : static char *convert_value_to_string(PLpgSQL_execstate *estate,
     408             :                                      Datum value, Oid valtype);
     409             : static Datum exec_cast_value(PLpgSQL_execstate *estate,
     410             :                              Datum value, bool *isnull,
     411             :                              Oid valtype, int32 valtypmod,
     412             :                              Oid reqtype, int32 reqtypmod);
     413             : static plpgsql_CastHashEntry *get_cast_hashentry(PLpgSQL_execstate *estate,
     414             :                                                  Oid srctype, int32 srctypmod,
     415             :                                                  Oid dsttype, int32 dsttypmod);
     416             : static void exec_init_tuple_store(PLpgSQL_execstate *estate);
     417             : static void exec_set_found(PLpgSQL_execstate *estate, bool state);
     418             : static void plpgsql_create_econtext(PLpgSQL_execstate *estate);
     419             : static void plpgsql_destroy_econtext(PLpgSQL_execstate *estate);
     420             : static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var,
     421             :                               Datum newvalue, bool isnull, bool freeable);
     422             : static void assign_text_var(PLpgSQL_execstate *estate, PLpgSQL_var *var,
     423             :                             const char *str);
     424             : static void assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec,
     425             :                               ExpandedRecordHeader *erh);
     426             : static PreparedParamsData *exec_eval_using_params(PLpgSQL_execstate *estate,
     427             :                                                   List *params);
     428             : static Portal exec_dynquery_with_params(PLpgSQL_execstate *estate,
     429             :                                         PLpgSQL_expr *dynquery, List *params,
     430             :                                         const char *portalname, int cursorOptions);
     431             : static char *format_expr_params(PLpgSQL_execstate *estate,
     432             :                                 const PLpgSQL_expr *expr);
     433             : static char *format_preparedparamsdata(PLpgSQL_execstate *estate,
     434             :                                        const PreparedParamsData *ppd);
     435             : 
     436             : 
     437             : /* ----------
     438             :  * plpgsql_exec_function    Called by the call handler for
     439             :  *              function execution.
     440             :  *
     441             :  * This is also used to execute inline code blocks (DO blocks).  The only
     442             :  * difference that this code is aware of is that for a DO block, we want
     443             :  * to use a private simple_eval_estate, which is created and passed in by
     444             :  * the caller.  For regular functions, pass NULL, which implies using
     445             :  * shared_simple_eval_estate.  (When using a private simple_eval_estate,
     446             :  * we must also use a private cast hashtable, but that's taken care of
     447             :  * within plpgsql_estate_setup.)
     448             :  * ----------
     449             :  */
     450             : Datum
     451       55462 : plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
     452             :                       EState *simple_eval_estate, bool atomic)
     453             : {
     454             :     PLpgSQL_execstate estate;
     455             :     ErrorContextCallback plerrcontext;
     456             :     int         i;
     457             :     int         rc;
     458             : 
     459             :     /*
     460             :      * Setup the execution state
     461             :      */
     462       55462 :     plpgsql_estate_setup(&estate, func, (ReturnSetInfo *) fcinfo->resultinfo,
     463             :                          simple_eval_estate);
     464       55462 :     estate.atomic = atomic;
     465             : 
     466             :     /*
     467             :      * Setup error traceback support for ereport()
     468             :      */
     469       55462 :     plerrcontext.callback = plpgsql_exec_error_callback;
     470       55462 :     plerrcontext.arg = &estate;
     471       55462 :     plerrcontext.previous = error_context_stack;
     472       55462 :     error_context_stack = &plerrcontext;
     473             : 
     474             :     /*
     475             :      * Make local execution copies of all the datums
     476             :      */
     477       55462 :     estate.err_text = gettext_noop("during initialization of execution state");
     478       55462 :     copy_plpgsql_datums(&estate, func);
     479             : 
     480             :     /*
     481             :      * Store the actual call argument values into the appropriate variables
     482             :      */
     483       55462 :     estate.err_text = gettext_noop("while storing call arguments into local variables");
     484      134560 :     for (i = 0; i < func->fn_nargs; i++)
     485             :     {
     486       79098 :         int         n = func->fn_argvarnos[i];
     487             : 
     488       79098 :         switch (estate.datums[n]->dtype)
     489             :         {
     490             :             case PLPGSQL_DTYPE_VAR:
     491             :                 {
     492       78906 :                     PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[n];
     493             : 
     494       78906 :                     assign_simple_var(&estate, var,
     495             :                                       fcinfo->args[i].value,
     496       78906 :                                       fcinfo->args[i].isnull,
     497             :                                       false);
     498             : 
     499             :                     /*
     500             :                      * Force any array-valued parameter to be stored in
     501             :                      * expanded form in our local variable, in hopes of
     502             :                      * improving efficiency of uses of the variable.  (This is
     503             :                      * a hack, really: why only arrays? Need more thought
     504             :                      * about which cases are likely to win.  See also
     505             :                      * typisarray-specific heuristic in exec_assign_value.)
     506             :                      *
     507             :                      * Special cases: If passed a R/W expanded pointer, assume
     508             :                      * we can commandeer the object rather than having to copy
     509             :                      * it.  If passed a R/O expanded pointer, just keep it as
     510             :                      * the value of the variable for the moment.  (We'll force
     511             :                      * it to R/W if the variable gets modified, but that may
     512             :                      * very well never happen.)
     513             :                      */
     514       78906 :                     if (!var->isnull && var->datatype->typisarray)
     515             :                     {
     516        3322 :                         if (VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(var->value)))
     517             :                         {
     518             :                             /* take ownership of R/W object */
     519           4 :                             assign_simple_var(&estate, var,
     520             :                                               TransferExpandedObject(var->value,
     521             :                                                                      estate.datum_context),
     522             :                                               false,
     523             :                                               true);
     524             :                         }
     525        3318 :                         else if (VARATT_IS_EXTERNAL_EXPANDED_RO(DatumGetPointer(var->value)))
     526             :                         {
     527             :                             /* R/O pointer, keep it as-is until assigned to */
     528             :                         }
     529             :                         else
     530             :                         {
     531             :                             /* flat array, so force to expanded form */
     532        3286 :                             assign_simple_var(&estate, var,
     533             :                                               expand_array(var->value,
     534             :                                                            estate.datum_context,
     535             :                                                            NULL),
     536             :                                               false,
     537             :                                               true);
     538             :                         }
     539             :                     }
     540             :                 }
     541       78906 :                 break;
     542             : 
     543             :             case PLPGSQL_DTYPE_REC:
     544             :                 {
     545         192 :                     PLpgSQL_rec *rec = (PLpgSQL_rec *) estate.datums[n];
     546             : 
     547         192 :                     if (!fcinfo->args[i].isnull)
     548             :                     {
     549             :                         /* Assign row value from composite datum */
     550         150 :                         exec_move_row_from_datum(&estate,
     551             :                                                  (PLpgSQL_variable *) rec,
     552             :                                                  fcinfo->args[i].value);
     553             :                     }
     554             :                     else
     555             :                     {
     556             :                         /* If arg is null, set variable to null */
     557          42 :                         exec_move_row(&estate, (PLpgSQL_variable *) rec,
     558             :                                       NULL, NULL);
     559             :                     }
     560             :                     /* clean up after exec_move_row() */
     561         192 :                     exec_eval_cleanup(&estate);
     562             :                 }
     563         192 :                 break;
     564             : 
     565             :             default:
     566             :                 /* Anything else should not be an argument variable */
     567           0 :                 elog(ERROR, "unrecognized dtype: %d", func->datums[i]->dtype);
     568             :         }
     569             :     }
     570             : 
     571       55462 :     estate.err_text = gettext_noop("during function entry");
     572             : 
     573             :     /*
     574             :      * Set the magic variable FOUND to false
     575             :      */
     576       55462 :     exec_set_found(&estate, false);
     577             : 
     578             :     /*
     579             :      * Let the instrumentation plugin peek at this function
     580             :      */
     581       55462 :     if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_beg)
     582           0 :         ((*plpgsql_plugin_ptr)->func_beg) (&estate, func);
     583             : 
     584             :     /*
     585             :      * Now call the toplevel block of statements
     586             :      */
     587       55462 :     estate.err_text = NULL;
     588       55462 :     estate.err_stmt = (PLpgSQL_stmt *) (func->action);
     589       55462 :     rc = exec_stmt(&estate, (PLpgSQL_stmt *) func->action);
     590       54932 :     if (rc != PLPGSQL_RC_RETURN)
     591             :     {
     592           4 :         estate.err_stmt = NULL;
     593           4 :         estate.err_text = NULL;
     594           4 :         ereport(ERROR,
     595             :                 (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
     596             :                  errmsg("control reached end of function without RETURN")));
     597             :     }
     598             : 
     599             :     /*
     600             :      * We got a return value - process it
     601             :      */
     602       54928 :     estate.err_stmt = NULL;
     603       54928 :     estate.err_text = gettext_noop("while casting return value to function's return type");
     604             : 
     605       54928 :     fcinfo->isnull = estate.retisnull;
     606             : 
     607       54928 :     if (estate.retisset)
     608             :     {
     609         688 :         ReturnSetInfo *rsi = estate.rsi;
     610             : 
     611             :         /* Check caller can handle a set result */
     612        1376 :         if (!rsi || !IsA(rsi, ReturnSetInfo) ||
     613         688 :             (rsi->allowedModes & SFRM_Materialize) == 0)
     614           0 :             ereport(ERROR,
     615             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     616             :                      errmsg("set-valued function called in context that cannot accept a set")));
     617         688 :         rsi->returnMode = SFRM_Materialize;
     618             : 
     619             :         /* If we produced any tuples, send back the result */
     620         688 :         if (estate.tuple_store)
     621             :         {
     622             :             MemoryContext oldcxt;
     623             : 
     624         676 :             rsi->setResult = estate.tuple_store;
     625         676 :             oldcxt = MemoryContextSwitchTo(estate.tuple_store_cxt);
     626         676 :             rsi->setDesc = CreateTupleDescCopy(estate.tuple_store_desc);
     627         676 :             MemoryContextSwitchTo(oldcxt);
     628             :         }
     629         688 :         estate.retval = (Datum) 0;
     630         688 :         fcinfo->isnull = true;
     631             :     }
     632       54240 :     else if (!estate.retisnull)
     633             :     {
     634             :         /*
     635             :          * Cast result value to function's declared result type, and copy it
     636             :          * out to the upper executor memory context.  We must treat tuple
     637             :          * results specially in order to deal with cases like rowtypes
     638             :          * involving dropped columns.
     639             :          */
     640       54088 :         if (estate.retistuple)
     641             :         {
     642             :             /* Don't need coercion if rowtype is known to match */
     643         638 :             if (func->fn_rettype == estate.rettype &&
     644         292 :                 func->fn_rettype != RECORDOID)
     645             :             {
     646             :                 /*
     647             :                  * Copy the tuple result into upper executor memory context.
     648             :                  * However, if we have a R/W expanded datum, we can just
     649             :                  * transfer its ownership out to the upper context.
     650             :                  */
     651         152 :                 estate.retval = SPI_datumTransfer(estate.retval,
     652             :                                                   false,
     653             :                                                   -1);
     654             :             }
     655             :             else
     656             :             {
     657             :                 /*
     658             :                  * Need to look up the expected result type.  XXX would be
     659             :                  * better to cache the tupdesc instead of repeating
     660             :                  * get_call_result_type(), but the only easy place to save it
     661             :                  * is in the PLpgSQL_function struct, and that's too
     662             :                  * long-lived: composite types could change during the
     663             :                  * existence of a PLpgSQL_function.
     664             :                  */
     665             :                 Oid         resultTypeId;
     666             :                 TupleDesc   tupdesc;
     667             : 
     668         194 :                 switch (get_call_result_type(fcinfo, &resultTypeId, &tupdesc))
     669             :                 {
     670             :                     case TYPEFUNC_COMPOSITE:
     671             :                         /* got the expected result rowtype, now coerce it */
     672         138 :                         coerce_function_result_tuple(&estate, tupdesc);
     673         110 :                         break;
     674             :                     case TYPEFUNC_COMPOSITE_DOMAIN:
     675             :                         /* got the expected result rowtype, now coerce it */
     676          16 :                         coerce_function_result_tuple(&estate, tupdesc);
     677             :                         /* and check domain constraints */
     678             :                         /* XXX allowing caching here would be good, too */
     679          16 :                         domain_check(estate.retval, false, resultTypeId,
     680             :                                      NULL, NULL);
     681           8 :                         break;
     682             :                     case TYPEFUNC_RECORD:
     683             : 
     684             :                         /*
     685             :                          * Failed to determine actual type of RECORD.  We
     686             :                          * could raise an error here, but what this means in
     687             :                          * practice is that the caller is expecting any old
     688             :                          * generic rowtype, so we don't really need to be
     689             :                          * restrictive.  Pass back the generated result as-is.
     690             :                          */
     691          40 :                         estate.retval = SPI_datumTransfer(estate.retval,
     692             :                                                           false,
     693             :                                                           -1);
     694          40 :                         break;
     695             :                     default:
     696             :                         /* shouldn't get here if retistuple is true ... */
     697           0 :                         elog(ERROR, "return type must be a row type");
     698             :                         break;
     699             :                 }
     700             :             }
     701             :         }
     702             :         else
     703             :         {
     704             :             /* Scalar case: use exec_cast_value */
     705       53742 :             estate.retval = exec_cast_value(&estate,
     706             :                                             estate.retval,
     707             :                                             &fcinfo->isnull,
     708             :                                             estate.rettype,
     709             :                                             -1,
     710             :                                             func->fn_rettype,
     711             :                                             -1);
     712             : 
     713             :             /*
     714             :              * If the function's return type isn't by value, copy the value
     715             :              * into upper executor memory context.  However, if we have a R/W
     716             :              * expanded datum, we can just transfer its ownership out to the
     717             :              * upper executor context.
     718             :              */
     719       53714 :             if (!fcinfo->isnull && !func->fn_retbyval)
     720        4378 :                 estate.retval = SPI_datumTransfer(estate.retval,
     721             :                                                   false,
     722             :                                                   func->fn_rettyplen);
     723             :         }
     724             :     }
     725             :     else
     726             :     {
     727             :         /*
     728             :          * We're returning a NULL, which normally requires no conversion work
     729             :          * regardless of datatypes.  But, if we are casting it to a domain
     730             :          * return type, we'd better check that the domain's constraints pass.
     731             :          */
     732         152 :         if (func->fn_retisdomain)
     733           4 :             estate.retval = exec_cast_value(&estate,
     734             :                                             estate.retval,
     735             :                                             &fcinfo->isnull,
     736             :                                             estate.rettype,
     737             :                                             -1,
     738             :                                             func->fn_rettype,
     739             :                                             -1);
     740             :     }
     741             : 
     742       54862 :     estate.err_text = gettext_noop("during function exit");
     743             : 
     744             :     /*
     745             :      * Let the instrumentation plugin peek at this function
     746             :      */
     747       54862 :     if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_end)
     748           0 :         ((*plpgsql_plugin_ptr)->func_end) (&estate, func);
     749             : 
     750             :     /* Clean up any leftover temporary memory */
     751       54862 :     plpgsql_destroy_econtext(&estate);
     752       54862 :     exec_eval_cleanup(&estate);
     753             :     /* stmt_mcontext will be destroyed when function's main context is */
     754             : 
     755             :     /*
     756             :      * Pop the error context stack
     757             :      */
     758       54862 :     error_context_stack = plerrcontext.previous;
     759             : 
     760             :     /*
     761             :      * Return the function's result
     762             :      */
     763       54862 :     return estate.retval;
     764             : }
     765             : 
     766             : /*
     767             :  * Helper for plpgsql_exec_function: coerce composite result to the specified
     768             :  * tuple descriptor, and copy it out to upper executor memory.  This is split
     769             :  * out mostly for cosmetic reasons --- the logic would be very deeply nested
     770             :  * otherwise.
     771             :  *
     772             :  * estate->retval is updated in-place.
     773             :  */
     774             : static void
     775         154 : coerce_function_result_tuple(PLpgSQL_execstate *estate, TupleDesc tupdesc)
     776             : {
     777             :     HeapTuple   rettup;
     778             :     TupleDesc   retdesc;
     779             :     TupleConversionMap *tupmap;
     780             : 
     781             :     /* We assume exec_stmt_return verified that result is composite */
     782             :     Assert(type_is_rowtype(estate->rettype));
     783             : 
     784             :     /* We can special-case expanded records for speed */
     785         154 :     if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(estate->retval)))
     786          28 :     {
     787          40 :         ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(estate->retval);
     788             : 
     789             :         Assert(erh->er_magic == ER_MAGIC);
     790             : 
     791             :         /* Extract record's TupleDesc */
     792          40 :         retdesc = expanded_record_get_tupdesc(erh);
     793             : 
     794             :         /* check rowtype compatibility */
     795          40 :         tupmap = convert_tuples_by_position(retdesc,
     796             :                                             tupdesc,
     797             :                                             gettext_noop("returned record type does not match expected record type"));
     798             : 
     799             :         /* it might need conversion */
     800          28 :         if (tupmap)
     801             :         {
     802           2 :             rettup = expanded_record_get_tuple(erh);
     803             :             Assert(rettup);
     804           2 :             rettup = execute_attr_map_tuple(rettup, tupmap);
     805             : 
     806             :             /*
     807             :              * Copy tuple to upper executor memory, as a tuple Datum.  Make
     808             :              * sure it is labeled with the caller-supplied tuple type.
     809             :              */
     810           2 :             estate->retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
     811             :             /* no need to free map, we're about to return anyway */
     812             :         }
     813          38 :         else if (!(tupdesc->tdtypeid == erh->er_decltypeid ||
     814          12 :                    (tupdesc->tdtypeid == RECORDOID &&
     815           0 :                     !ExpandedRecordIsDomain(erh))))
     816          12 :         {
     817             :             /*
     818             :              * The expanded record has the right physical tupdesc, but the
     819             :              * wrong type ID.  (Typically, the expanded record is RECORDOID
     820             :              * but the function is declared to return a named composite type.
     821             :              * As in exec_move_row_from_datum, we don't allow returning a
     822             :              * composite-domain record from a function declared to return
     823             :              * RECORD.)  So we must flatten the record to a tuple datum and
     824             :              * overwrite its type fields with the right thing.  spi.c doesn't
     825             :              * provide any easy way to deal with this case, so we end up
     826             :              * duplicating the guts of datumCopy() :-(
     827             :              */
     828             :             Size        resultsize;
     829             :             HeapTupleHeader tuphdr;
     830             : 
     831          12 :             resultsize = EOH_get_flat_size(&erh->hdr);
     832          12 :             tuphdr = (HeapTupleHeader) SPI_palloc(resultsize);
     833          12 :             EOH_flatten_into(&erh->hdr, (void *) tuphdr, resultsize);
     834          12 :             HeapTupleHeaderSetTypeId(tuphdr, tupdesc->tdtypeid);
     835          12 :             HeapTupleHeaderSetTypMod(tuphdr, tupdesc->tdtypmod);
     836          12 :             estate->retval = PointerGetDatum(tuphdr);
     837             :         }
     838             :         else
     839             :         {
     840             :             /*
     841             :              * We need only copy result into upper executor memory context.
     842             :              * However, if we have a R/W expanded datum, we can just transfer
     843             :              * its ownership out to the upper executor context.
     844             :              */
     845          14 :             estate->retval = SPI_datumTransfer(estate->retval,
     846             :                                                false,
     847             :                                                -1);
     848             :         }
     849             :     }
     850             :     else
     851             :     {
     852             :         /* Convert composite datum to a HeapTuple and TupleDesc */
     853             :         HeapTupleData tmptup;
     854             : 
     855         114 :         retdesc = deconstruct_composite_datum(estate->retval, &tmptup);
     856         114 :         rettup = &tmptup;
     857             : 
     858             :         /* check rowtype compatibility */
     859         114 :         tupmap = convert_tuples_by_position(retdesc,
     860             :                                             tupdesc,
     861             :                                             gettext_noop("returned record type does not match expected record type"));
     862             : 
     863             :         /* it might need conversion */
     864          98 :         if (tupmap)
     865           2 :             rettup = execute_attr_map_tuple(rettup, tupmap);
     866             : 
     867             :         /*
     868             :          * Copy tuple to upper executor memory, as a tuple Datum.  Make sure
     869             :          * it is labeled with the caller-supplied tuple type.
     870             :          */
     871          98 :         estate->retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
     872             : 
     873             :         /* no need to free map, we're about to return anyway */
     874             : 
     875          98 :         ReleaseTupleDesc(retdesc);
     876             :     }
     877         126 : }
     878             : 
     879             : 
     880             : /* ----------
     881             :  * plpgsql_exec_trigger     Called by the call handler for
     882             :  *              trigger execution.
     883             :  * ----------
     884             :  */
     885             : HeapTuple
     886        9154 : plpgsql_exec_trigger(PLpgSQL_function *func,
     887             :                      TriggerData *trigdata)
     888             : {
     889             :     PLpgSQL_execstate estate;
     890             :     ErrorContextCallback plerrcontext;
     891             :     int         rc;
     892             :     TupleDesc   tupdesc;
     893             :     PLpgSQL_rec *rec_new,
     894             :                *rec_old;
     895             :     HeapTuple   rettup;
     896             : 
     897             :     /*
     898             :      * Setup the execution state
     899             :      */
     900        9154 :     plpgsql_estate_setup(&estate, func, NULL, NULL);
     901        9154 :     estate.trigdata = trigdata;
     902             : 
     903             :     /*
     904             :      * Setup error traceback support for ereport()
     905             :      */
     906        9154 :     plerrcontext.callback = plpgsql_exec_error_callback;
     907        9154 :     plerrcontext.arg = &estate;
     908        9154 :     plerrcontext.previous = error_context_stack;
     909        9154 :     error_context_stack = &plerrcontext;
     910             : 
     911             :     /*
     912             :      * Make local execution copies of all the datums
     913             :      */
     914        9154 :     estate.err_text = gettext_noop("during initialization of execution state");
     915        9154 :     copy_plpgsql_datums(&estate, func);
     916             : 
     917             :     /*
     918             :      * Put the OLD and NEW tuples into record variables
     919             :      *
     920             :      * We set up expanded records for both variables even though only one may
     921             :      * have a value.  This allows record references to succeed in functions
     922             :      * that are used for multiple trigger types.  For example, we might have a
     923             :      * test like "if (TG_OP = 'INSERT' and NEW.foo = 'xyz')", which should
     924             :      * work regardless of the current trigger type.  If a value is actually
     925             :      * fetched from an unsupplied tuple, it will read as NULL.
     926             :      */
     927        9154 :     tupdesc = RelationGetDescr(trigdata->tg_relation);
     928             : 
     929        9154 :     rec_new = (PLpgSQL_rec *) (estate.datums[func->new_varno]);
     930        9154 :     rec_old = (PLpgSQL_rec *) (estate.datums[func->old_varno]);
     931             : 
     932        9154 :     rec_new->erh = make_expanded_record_from_tupdesc(tupdesc,
     933             :                                                      estate.datum_context);
     934        9154 :     rec_old->erh = make_expanded_record_from_exprecord(rec_new->erh,
     935             :                                                        estate.datum_context);
     936             : 
     937        9154 :     if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
     938             :     {
     939             :         /*
     940             :          * Per-statement triggers don't use OLD/NEW variables
     941             :          */
     942             :     }
     943        8444 :     else if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
     944             :     {
     945        4138 :         expanded_record_set_tuple(rec_new->erh, trigdata->tg_trigtuple,
     946             :                                   false, false);
     947             :     }
     948        4306 :     else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
     949             :     {
     950        4126 :         expanded_record_set_tuple(rec_new->erh, trigdata->tg_newtuple,
     951             :                                   false, false);
     952        4126 :         expanded_record_set_tuple(rec_old->erh, trigdata->tg_trigtuple,
     953             :                                   false, false);
     954             : 
     955             :         /*
     956             :          * In BEFORE trigger, stored generated columns are not computed yet,
     957             :          * so make them null in the NEW row.  (Only needed in UPDATE branch;
     958             :          * in the INSERT case, they are already null, but in UPDATE, the field
     959             :          * still contains the old value.)  Alternatively, we could construct a
     960             :          * whole new row structure without the generated columns, but this way
     961             :          * seems more efficient and potentially less confusing.
     962             :          */
     963        4154 :         if (tupdesc->constr && tupdesc->constr->has_generated_stored &&
     964          28 :             TRIGGER_FIRED_BEFORE(trigdata->tg_event))
     965             :         {
     966          60 :             for (int i = 0; i < tupdesc->natts; i++)
     967          40 :                 if (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED)
     968          20 :                     expanded_record_set_field_internal(rec_new->erh,
     969             :                                                        i + 1,
     970             :                                                        (Datum) 0,
     971             :                                                        true,    /* isnull */
     972             :                                                        false, false);
     973             :         }
     974             :     }
     975         180 :     else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
     976             :     {
     977         180 :         expanded_record_set_tuple(rec_old->erh, trigdata->tg_trigtuple,
     978             :                                   false, false);
     979             :     }
     980             :     else
     981           0 :         elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, or UPDATE");
     982             : 
     983             :     /* Make transition tables visible to this SPI connection */
     984        9154 :     rc = SPI_register_trigger_data(trigdata);
     985             :     Assert(rc >= 0);
     986             : 
     987        9154 :     estate.err_text = gettext_noop("during function entry");
     988             : 
     989             :     /*
     990             :      * Set the magic variable FOUND to false
     991             :      */
     992        9154 :     exec_set_found(&estate, false);
     993             : 
     994             :     /*
     995             :      * Let the instrumentation plugin peek at this function
     996             :      */
     997        9154 :     if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_beg)
     998           0 :         ((*plpgsql_plugin_ptr)->func_beg) (&estate, func);
     999             : 
    1000             :     /*
    1001             :      * Now call the toplevel block of statements
    1002             :      */
    1003        9154 :     estate.err_text = NULL;
    1004        9154 :     estate.err_stmt = (PLpgSQL_stmt *) (func->action);
    1005        9154 :     rc = exec_stmt(&estate, (PLpgSQL_stmt *) func->action);
    1006        9058 :     if (rc != PLPGSQL_RC_RETURN)
    1007             :     {
    1008           0 :         estate.err_stmt = NULL;
    1009           0 :         estate.err_text = NULL;
    1010           0 :         ereport(ERROR,
    1011             :                 (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
    1012             :                  errmsg("control reached end of trigger procedure without RETURN")));
    1013             :     }
    1014             : 
    1015        9058 :     estate.err_stmt = NULL;
    1016        9058 :     estate.err_text = gettext_noop("during function exit");
    1017             : 
    1018        9058 :     if (estate.retisset)
    1019           0 :         ereport(ERROR,
    1020             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    1021             :                  errmsg("trigger procedure cannot return a set")));
    1022             : 
    1023             :     /*
    1024             :      * Check that the returned tuple structure has the same attributes, the
    1025             :      * relation that fired the trigger has. A per-statement trigger always
    1026             :      * needs to return NULL, so we ignore any return value the function itself
    1027             :      * produces (XXX: is this a good idea?)
    1028             :      *
    1029             :      * XXX This way it is possible, that the trigger returns a tuple where
    1030             :      * attributes don't have the correct atttypmod's length. It's up to the
    1031             :      * trigger's programmer to ensure that this doesn't happen. Jan
    1032             :      */
    1033        9058 :     if (estate.retisnull || !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
    1034        1130 :         rettup = NULL;
    1035             :     else
    1036             :     {
    1037             :         TupleDesc   retdesc;
    1038             :         TupleConversionMap *tupmap;
    1039             : 
    1040             :         /* We assume exec_stmt_return verified that result is composite */
    1041             :         Assert(type_is_rowtype(estate.rettype));
    1042             : 
    1043             :         /* We can special-case expanded records for speed */
    1044        7928 :         if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(estate.retval)))
    1045        7924 :         {
    1046        7924 :             ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(estate.retval);
    1047             : 
    1048             :             Assert(erh->er_magic == ER_MAGIC);
    1049             : 
    1050             :             /* Extract HeapTuple and TupleDesc */
    1051        7924 :             rettup = expanded_record_get_tuple(erh);
    1052             :             Assert(rettup);
    1053        7924 :             retdesc = expanded_record_get_tupdesc(erh);
    1054             : 
    1055        7924 :             if (retdesc != RelationGetDescr(trigdata->tg_relation))
    1056             :             {
    1057             :                 /* check rowtype compatibility */
    1058           4 :                 tupmap = convert_tuples_by_position(retdesc,
    1059           4 :                                                     RelationGetDescr(trigdata->tg_relation),
    1060             :                                                     gettext_noop("returned row structure does not match the structure of the triggering table"));
    1061             :                 /* it might need conversion */
    1062           4 :                 if (tupmap)
    1063           4 :                     rettup = execute_attr_map_tuple(rettup, tupmap);
    1064             :                 /* no need to free map, we're about to return anyway */
    1065             :             }
    1066             : 
    1067             :             /*
    1068             :              * Copy tuple to upper executor memory.  But if user just did
    1069             :              * "return new" or "return old" without changing anything, there's
    1070             :              * no need to copy; we can return the original tuple (which will
    1071             :              * save a few cycles in trigger.c as well as here).
    1072             :              */
    1073       12992 :             if (rettup != trigdata->tg_newtuple &&
    1074        5068 :                 rettup != trigdata->tg_trigtuple)
    1075        1464 :                 rettup = SPI_copytuple(rettup);
    1076             :         }
    1077             :         else
    1078             :         {
    1079             :             /* Convert composite datum to a HeapTuple and TupleDesc */
    1080             :             HeapTupleData tmptup;
    1081             : 
    1082           4 :             retdesc = deconstruct_composite_datum(estate.retval, &tmptup);
    1083           4 :             rettup = &tmptup;
    1084             : 
    1085             :             /* check rowtype compatibility */
    1086           4 :             tupmap = convert_tuples_by_position(retdesc,
    1087           4 :                                                 RelationGetDescr(trigdata->tg_relation),
    1088             :                                                 gettext_noop("returned row structure does not match the structure of the triggering table"));
    1089             :             /* it might need conversion */
    1090           4 :             if (tupmap)
    1091           4 :                 rettup = execute_attr_map_tuple(rettup, tupmap);
    1092             : 
    1093           4 :             ReleaseTupleDesc(retdesc);
    1094             :             /* no need to free map, we're about to return anyway */
    1095             : 
    1096             :             /* Copy tuple to upper executor memory */
    1097           4 :             rettup = SPI_copytuple(rettup);
    1098             :         }
    1099             :     }
    1100             : 
    1101             :     /*
    1102             :      * Let the instrumentation plugin peek at this function
    1103             :      */
    1104        9058 :     if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_end)
    1105           0 :         ((*plpgsql_plugin_ptr)->func_end) (&estate, func);
    1106             : 
    1107             :     /* Clean up any leftover temporary memory */
    1108        9058 :     plpgsql_destroy_econtext(&estate);
    1109        9058 :     exec_eval_cleanup(&estate);
    1110             :     /* stmt_mcontext will be destroyed when function's main context is */
    1111             : 
    1112             :     /*
    1113             :      * Pop the error context stack
    1114             :      */
    1115        9058 :     error_context_stack = plerrcontext.previous;
    1116             : 
    1117             :     /*
    1118             :      * Return the trigger's result
    1119             :      */
    1120        9058 :     return rettup;
    1121             : }
    1122             : 
    1123             : /* ----------
    1124             :  * plpgsql_exec_event_trigger       Called by the call handler for
    1125             :  *              event trigger execution.
    1126             :  * ----------
    1127             :  */
    1128             : void
    1129         652 : plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata)
    1130             : {
    1131             :     PLpgSQL_execstate estate;
    1132             :     ErrorContextCallback plerrcontext;
    1133             :     int         rc;
    1134             : 
    1135             :     /*
    1136             :      * Setup the execution state
    1137             :      */
    1138         652 :     plpgsql_estate_setup(&estate, func, NULL, NULL);
    1139         652 :     estate.evtrigdata = trigdata;
    1140             : 
    1141             :     /*
    1142             :      * Setup error traceback support for ereport()
    1143             :      */
    1144         652 :     plerrcontext.callback = plpgsql_exec_error_callback;
    1145         652 :     plerrcontext.arg = &estate;
    1146         652 :     plerrcontext.previous = error_context_stack;
    1147         652 :     error_context_stack = &plerrcontext;
    1148             : 
    1149             :     /*
    1150             :      * Make local execution copies of all the datums
    1151             :      */
    1152         652 :     estate.err_text = gettext_noop("during initialization of execution state");
    1153         652 :     copy_plpgsql_datums(&estate, func);
    1154             : 
    1155             :     /*
    1156             :      * Let the instrumentation plugin peek at this function
    1157             :      */
    1158         652 :     if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_beg)
    1159           0 :         ((*plpgsql_plugin_ptr)->func_beg) (&estate, func);
    1160             : 
    1161             :     /*
    1162             :      * Now call the toplevel block of statements
    1163             :      */
    1164         652 :     estate.err_text = NULL;
    1165         652 :     estate.err_stmt = (PLpgSQL_stmt *) (func->action);
    1166         652 :     rc = exec_stmt(&estate, (PLpgSQL_stmt *) func->action);
    1167         636 :     if (rc != PLPGSQL_RC_RETURN)
    1168             :     {
    1169           0 :         estate.err_stmt = NULL;
    1170           0 :         estate.err_text = NULL;
    1171           0 :         ereport(ERROR,
    1172             :                 (errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
    1173             :                  errmsg("control reached end of trigger procedure without RETURN")));
    1174             :     }
    1175             : 
    1176         636 :     estate.err_stmt = NULL;
    1177         636 :     estate.err_text = gettext_noop("during function exit");
    1178             : 
    1179             :     /*
    1180             :      * Let the instrumentation plugin peek at this function
    1181             :      */
    1182         636 :     if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_end)
    1183           0 :         ((*plpgsql_plugin_ptr)->func_end) (&estate, func);
    1184             : 
    1185             :     /* Clean up any leftover temporary memory */
    1186         636 :     plpgsql_destroy_econtext(&estate);
    1187         636 :     exec_eval_cleanup(&estate);
    1188             :     /* stmt_mcontext will be destroyed when function's main context is */
    1189             : 
    1190             :     /*
    1191             :      * Pop the error context stack
    1192             :      */
    1193         636 :     error_context_stack = plerrcontext.previous;
    1194             : 
    1195         636 :     return;
    1196             : }
    1197             : 
    1198             : /*
    1199             :  * error context callback to let us supply a call-stack traceback
    1200             :  */
    1201             : static void
    1202        8824 : plpgsql_exec_error_callback(void *arg)
    1203             : {
    1204        8824 :     PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;
    1205             : 
    1206        8824 :     if (estate->err_text != NULL)
    1207             :     {
    1208             :         /*
    1209             :          * We don't expend the cycles to run gettext() on err_text unless we
    1210             :          * actually need it.  Therefore, places that set up err_text should
    1211             :          * use gettext_noop() to ensure the strings get recorded in the
    1212             :          * message dictionary.
    1213             :          *
    1214             :          * If both err_text and err_stmt are set, use the err_text as
    1215             :          * description, but report the err_stmt's line number.  When err_stmt
    1216             :          * is not set, we're in function entry/exit, or some such place not
    1217             :          * attached to a specific line number.
    1218             :          */
    1219         112 :         if (estate->err_stmt != NULL)
    1220             :         {
    1221             :             /*
    1222             :              * translator: last %s is a phrase such as "during statement block
    1223             :              * local variable initialization"
    1224             :              */
    1225         138 :             errcontext("PL/pgSQL function %s line %d %s",
    1226          46 :                        estate->func->fn_signature,
    1227          46 :                        estate->err_stmt->lineno,
    1228             :                        _(estate->err_text));
    1229             :         }
    1230             :         else
    1231             :         {
    1232             :             /*
    1233             :              * translator: last %s is a phrase such as "while storing call
    1234             :              * arguments into local variables"
    1235             :              */
    1236         132 :             errcontext("PL/pgSQL function %s %s",
    1237          66 :                        estate->func->fn_signature,
    1238             :                        _(estate->err_text));
    1239             :         }
    1240             :     }
    1241        8712 :     else if (estate->err_stmt != NULL)
    1242             :     {
    1243             :         /* translator: last %s is a plpgsql statement type name */
    1244       26124 :         errcontext("PL/pgSQL function %s line %d at %s",
    1245        8708 :                    estate->func->fn_signature,
    1246        8708 :                    estate->err_stmt->lineno,
    1247             :                    plpgsql_stmt_typename(estate->err_stmt));
    1248             :     }
    1249             :     else
    1250           8 :         errcontext("PL/pgSQL function %s",
    1251           4 :                    estate->func->fn_signature);
    1252        8824 : }
    1253             : 
    1254             : 
    1255             : /* ----------
    1256             :  * Support function for initializing local execution variables
    1257             :  * ----------
    1258             :  */
    1259             : static void
    1260       65268 : copy_plpgsql_datums(PLpgSQL_execstate *estate,
    1261             :                     PLpgSQL_function *func)
    1262             : {
    1263       65268 :     int         ndatums = estate->ndatums;
    1264             :     PLpgSQL_datum **indatums;
    1265             :     PLpgSQL_datum **outdatums;
    1266             :     char       *workspace;
    1267             :     char       *ws_next;
    1268             :     int         i;
    1269             : 
    1270             :     /* Allocate local datum-pointer array */
    1271       65268 :     estate->datums = (PLpgSQL_datum **)
    1272       65268 :         palloc(sizeof(PLpgSQL_datum *) * ndatums);
    1273             : 
    1274             :     /*
    1275             :      * To reduce palloc overhead, we make a single palloc request for all the
    1276             :      * space needed for locally-instantiated datums.
    1277             :      */
    1278       65268 :     workspace = palloc(func->copiable_size);
    1279       65268 :     ws_next = workspace;
    1280             : 
    1281             :     /* Fill datum-pointer array, copying datums into workspace as needed */
    1282       65268 :     indatums = func->datums;
    1283       65268 :     outdatums = estate->datums;
    1284      359048 :     for (i = 0; i < ndatums; i++)
    1285             :     {
    1286      293780 :         PLpgSQL_datum *indatum = indatums[i];
    1287             :         PLpgSQL_datum *outdatum;
    1288             : 
    1289             :         /* This must agree with plpgsql_finish_datums on what is copiable */
    1290      293780 :         switch (indatum->dtype)
    1291             :         {
    1292             :             case PLPGSQL_DTYPE_VAR:
    1293             :             case PLPGSQL_DTYPE_PROMISE:
    1294      249502 :                 outdatum = (PLpgSQL_datum *) ws_next;
    1295      249502 :                 memcpy(outdatum, indatum, sizeof(PLpgSQL_var));
    1296      249502 :                 ws_next += MAXALIGN(sizeof(PLpgSQL_var));
    1297      249502 :                 break;
    1298             : 
    1299             :             case PLPGSQL_DTYPE_REC:
    1300       21520 :                 outdatum = (PLpgSQL_datum *) ws_next;
    1301       21520 :                 memcpy(outdatum, indatum, sizeof(PLpgSQL_rec));
    1302       21520 :                 ws_next += MAXALIGN(sizeof(PLpgSQL_rec));
    1303       21520 :                 break;
    1304             : 
    1305             :             case PLPGSQL_DTYPE_ROW:
    1306             :             case PLPGSQL_DTYPE_RECFIELD:
    1307             :             case PLPGSQL_DTYPE_ARRAYELEM:
    1308             : 
    1309             :                 /*
    1310             :                  * These datum records are read-only at runtime, so no need to
    1311             :                  * copy them (well, RECFIELD and ARRAYELEM contain cached
    1312             :                  * data, but we'd just as soon centralize the caching anyway).
    1313             :                  */
    1314       22758 :                 outdatum = indatum;
    1315       22758 :                 break;
    1316             : 
    1317             :             default:
    1318           0 :                 elog(ERROR, "unrecognized dtype: %d", indatum->dtype);
    1319             :                 outdatum = NULL;    /* keep compiler quiet */
    1320             :                 break;
    1321             :         }
    1322             : 
    1323      293780 :         outdatums[i] = outdatum;
    1324             :     }
    1325             : 
    1326             :     Assert(ws_next == workspace + func->copiable_size);
    1327       65268 : }
    1328             : 
    1329             : /*
    1330             :  * If the variable has an armed "promise", compute the promised value
    1331             :  * and assign it to the variable.
    1332             :  * The assignment automatically disarms the promise.
    1333             :  */
    1334             : static void
    1335        9956 : plpgsql_fulfill_promise(PLpgSQL_execstate *estate,
    1336             :                         PLpgSQL_var *var)
    1337             : {
    1338             :     MemoryContext oldcontext;
    1339             : 
    1340        9956 :     if (var->promise == PLPGSQL_PROMISE_NONE)
    1341        1992 :         return;                 /* nothing to do */
    1342             : 
    1343             :     /*
    1344             :      * This will typically be invoked in a short-lived context such as the
    1345             :      * mcontext.  We must create variable values in the estate's datum
    1346             :      * context.  This quick-and-dirty solution risks leaking some additional
    1347             :      * cruft there, but since any one promise is honored at most once per
    1348             :      * function call, it's probably not worth being more careful.
    1349             :      */
    1350        7964 :     oldcontext = MemoryContextSwitchTo(estate->datum_context);
    1351             : 
    1352        7964 :     switch (var->promise)
    1353             :     {
    1354             :         case PLPGSQL_PROMISE_TG_NAME:
    1355         692 :             if (estate->trigdata == NULL)
    1356           0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1357         692 :             assign_simple_var(estate, var,
    1358         692 :                               DirectFunctionCall1(namein,
    1359             :                                                   CStringGetDatum(estate->trigdata->tg_trigger->tgname)),
    1360             :                               false, true);
    1361         692 :             break;
    1362             : 
    1363             :         case PLPGSQL_PROMISE_TG_WHEN:
    1364         964 :             if (estate->trigdata == NULL)
    1365           0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1366         964 :             if (TRIGGER_FIRED_BEFORE(estate->trigdata->tg_event))
    1367         352 :                 assign_text_var(estate, var, "BEFORE");
    1368         612 :             else if (TRIGGER_FIRED_AFTER(estate->trigdata->tg_event))
    1369         572 :                 assign_text_var(estate, var, "AFTER");
    1370          40 :             else if (TRIGGER_FIRED_INSTEAD(estate->trigdata->tg_event))
    1371          40 :                 assign_text_var(estate, var, "INSTEAD OF");
    1372             :             else
    1373           0 :                 elog(ERROR, "unrecognized trigger execution time: not BEFORE, AFTER, or INSTEAD OF");
    1374         964 :             break;
    1375             : 
    1376             :         case PLPGSQL_PROMISE_TG_LEVEL:
    1377         920 :             if (estate->trigdata == NULL)
    1378           0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1379         920 :             if (TRIGGER_FIRED_FOR_ROW(estate->trigdata->tg_event))
    1380         556 :                 assign_text_var(estate, var, "ROW");
    1381         364 :             else if (TRIGGER_FIRED_FOR_STATEMENT(estate->trigdata->tg_event))
    1382         364 :                 assign_text_var(estate, var, "STATEMENT");
    1383             :             else
    1384           0 :                 elog(ERROR, "unrecognized trigger event type: not ROW or STATEMENT");
    1385         920 :             break;
    1386             : 
    1387             :         case PLPGSQL_PROMISE_TG_OP:
    1388        3156 :             if (estate->trigdata == NULL)
    1389           0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1390        3156 :             if (TRIGGER_FIRED_BY_INSERT(estate->trigdata->tg_event))
    1391        1586 :                 assign_text_var(estate, var, "INSERT");
    1392        1570 :             else if (TRIGGER_FIRED_BY_UPDATE(estate->trigdata->tg_event))
    1393        1408 :                 assign_text_var(estate, var, "UPDATE");
    1394         162 :             else if (TRIGGER_FIRED_BY_DELETE(estate->trigdata->tg_event))
    1395         154 :                 assign_text_var(estate, var, "DELETE");
    1396           8 :             else if (TRIGGER_FIRED_BY_TRUNCATE(estate->trigdata->tg_event))
    1397           8 :                 assign_text_var(estate, var, "TRUNCATE");
    1398             :             else
    1399           0 :                 elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, UPDATE, or TRUNCATE");
    1400        3156 :             break;
    1401             : 
    1402             :         case PLPGSQL_PROMISE_TG_RELID:
    1403          96 :             if (estate->trigdata == NULL)
    1404           0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1405          96 :             assign_simple_var(estate, var,
    1406          96 :                               ObjectIdGetDatum(estate->trigdata->tg_relation->rd_id),
    1407             :                               false, false);
    1408          96 :             break;
    1409             : 
    1410             :         case PLPGSQL_PROMISE_TG_TABLE_NAME:
    1411         480 :             if (estate->trigdata == NULL)
    1412           0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1413         480 :             assign_simple_var(estate, var,
    1414         480 :                               DirectFunctionCall1(namein,
    1415             :                                                   CStringGetDatum(RelationGetRelationName(estate->trigdata->tg_relation))),
    1416             :                               false, true);
    1417         480 :             break;
    1418             : 
    1419             :         case PLPGSQL_PROMISE_TG_TABLE_SCHEMA:
    1420          12 :             if (estate->trigdata == NULL)
    1421           0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1422          12 :             assign_simple_var(estate, var,
    1423          12 :                               DirectFunctionCall1(namein,
    1424             :                                                   CStringGetDatum(get_namespace_name(RelationGetNamespace(estate->trigdata->tg_relation)))),
    1425             :                               false, true);
    1426          12 :             break;
    1427             : 
    1428             :         case PLPGSQL_PROMISE_TG_NARGS:
    1429         208 :             if (estate->trigdata == NULL)
    1430           0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1431         208 :             assign_simple_var(estate, var,
    1432         208 :                               Int16GetDatum(estate->trigdata->tg_trigger->tgnargs),
    1433             :                               false, false);
    1434         208 :             break;
    1435             : 
    1436             :         case PLPGSQL_PROMISE_TG_ARGV:
    1437        1168 :             if (estate->trigdata == NULL)
    1438           0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1439        1168 :             if (estate->trigdata->tg_trigger->tgnargs > 0)
    1440             :             {
    1441             :                 /*
    1442             :                  * For historical reasons, tg_argv[] subscripts start at zero
    1443             :                  * not one.  So we can't use construct_array().
    1444             :                  */
    1445        1148 :                 int         nelems = estate->trigdata->tg_trigger->tgnargs;
    1446             :                 Datum      *elems;
    1447             :                 int         dims[1];
    1448             :                 int         lbs[1];
    1449             :                 int         i;
    1450             : 
    1451        1148 :                 elems = palloc(sizeof(Datum) * nelems);
    1452        2404 :                 for (i = 0; i < nelems; i++)
    1453        1256 :                     elems[i] = CStringGetTextDatum(estate->trigdata->tg_trigger->tgargs[i]);
    1454        1148 :                 dims[0] = nelems;
    1455        1148 :                 lbs[0] = 0;
    1456             : 
    1457        1148 :                 assign_simple_var(estate, var,
    1458        1148 :                                   PointerGetDatum(construct_md_array(elems, NULL,
    1459             :                                                                      1, dims, lbs,
    1460             :                                                                      TEXTOID,
    1461             :                                                                      -1, false, 'i')),
    1462             :                                   false, true);
    1463             :             }
    1464             :             else
    1465             :             {
    1466          20 :                 assign_simple_var(estate, var, (Datum) 0, true, false);
    1467             :             }
    1468        1168 :             break;
    1469             : 
    1470             :         case PLPGSQL_PROMISE_TG_EVENT:
    1471         116 :             if (estate->evtrigdata == NULL)
    1472           0 :                 elog(ERROR, "event trigger promise is not in an event trigger function");
    1473         116 :             assign_text_var(estate, var, estate->evtrigdata->event);
    1474         116 :             break;
    1475             : 
    1476             :         case PLPGSQL_PROMISE_TG_TAG:
    1477         152 :             if (estate->evtrigdata == NULL)
    1478           0 :                 elog(ERROR, "event trigger promise is not in an event trigger function");
    1479         152 :             assign_text_var(estate, var, estate->evtrigdata->tag);
    1480         152 :             break;
    1481             : 
    1482             :         default:
    1483           0 :             elog(ERROR, "unrecognized promise type: %d", var->promise);
    1484             :     }
    1485             : 
    1486        7964 :     MemoryContextSwitchTo(oldcontext);
    1487             : }
    1488             : 
    1489             : /*
    1490             :  * Create a memory context for statement-lifespan variables, if we don't
    1491             :  * have one already.  It will be a child of stmt_mcontext_parent, which is
    1492             :  * either the function's main context or a pushed-down outer stmt_mcontext.
    1493             :  */
    1494             : static MemoryContext
    1495       19890 : get_stmt_mcontext(PLpgSQL_execstate *estate)
    1496             : {
    1497       19890 :     if (estate->stmt_mcontext == NULL)
    1498             :     {
    1499        7062 :         estate->stmt_mcontext =
    1500        7062 :             AllocSetContextCreate(estate->stmt_mcontext_parent,
    1501             :                                   "PLpgSQL per-statement data",
    1502             :                                   ALLOCSET_DEFAULT_SIZES);
    1503             :     }
    1504       19890 :     return estate->stmt_mcontext;
    1505             : }
    1506             : 
    1507             : /*
    1508             :  * Push down the current stmt_mcontext so that called statements won't use it.
    1509             :  * This is needed by statements that have statement-lifespan data and need to
    1510             :  * preserve it across some inner statements.  The caller should eventually do
    1511             :  * pop_stmt_mcontext().
    1512             :  */
    1513             : static void
    1514          60 : push_stmt_mcontext(PLpgSQL_execstate *estate)
    1515             : {
    1516             :     /* Should have done get_stmt_mcontext() first */
    1517             :     Assert(estate->stmt_mcontext != NULL);
    1518             :     /* Assert we've not messed up the stack linkage */
    1519             :     Assert(MemoryContextGetParent(estate->stmt_mcontext) == estate->stmt_mcontext_parent);
    1520             :     /* Push it down to become the parent of any nested stmt mcontext */
    1521          60 :     estate->stmt_mcontext_parent = estate->stmt_mcontext;
    1522             :     /* And make it not available for use directly */
    1523          60 :     estate->stmt_mcontext = NULL;
    1524          60 : }
    1525             : 
    1526             : /*
    1527             :  * Undo push_stmt_mcontext().  We assume this is done just before or after
    1528             :  * resetting the caller's stmt_mcontext; since that action will also delete
    1529             :  * any child contexts, there's no need to explicitly delete whatever context
    1530             :  * might currently be estate->stmt_mcontext.
    1531             :  */
    1532             : static void
    1533        1004 : pop_stmt_mcontext(PLpgSQL_execstate *estate)
    1534             : {
    1535             :     /* We need only pop the stack */
    1536        1004 :     estate->stmt_mcontext = estate->stmt_mcontext_parent;
    1537        1004 :     estate->stmt_mcontext_parent = MemoryContextGetParent(estate->stmt_mcontext);
    1538        1004 : }
    1539             : 
    1540             : 
    1541             : /*
    1542             :  * Subroutine for exec_stmt_block: does any condition in the condition list
    1543             :  * match the current exception?
    1544             :  */
    1545             : static bool
    1546        1002 : exception_matches_conditions(ErrorData *edata, PLpgSQL_condition *cond)
    1547             : {
    1548        1030 :     for (; cond != NULL; cond = cond->next)
    1549             :     {
    1550        1004 :         int         sqlerrstate = cond->sqlerrstate;
    1551             : 
    1552             :         /*
    1553             :          * OTHERS matches everything *except* query-canceled and
    1554             :          * assert-failure.  If you're foolish enough, you can match those
    1555             :          * explicitly.
    1556             :          */
    1557        1004 :         if (sqlerrstate == 0)
    1558             :         {
    1559        1702 :             if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED &&
    1560         850 :                 edata->sqlerrcode != ERRCODE_ASSERT_FAILURE)
    1561         846 :                 return true;
    1562             :         }
    1563             :         /* Exact match? */
    1564         152 :         else if (edata->sqlerrcode == sqlerrstate)
    1565         126 :             return true;
    1566             :         /* Category match? */
    1567          32 :         else if (ERRCODE_IS_CATEGORY(sqlerrstate) &&
    1568           6 :                  ERRCODE_TO_CATEGORY(edata->sqlerrcode) == sqlerrstate)
    1569           4 :             return true;
    1570             :     }
    1571          26 :     return false;
    1572             : }
    1573             : 
    1574             : 
    1575             : /* ----------
    1576             :  * exec_stmt_block          Execute a block of statements
    1577             :  * ----------
    1578             :  */
    1579             : static int
    1580       69318 : exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
    1581             : {
    1582       69318 :     volatile int rc = -1;
    1583             :     int         i;
    1584             : 
    1585             :     /*
    1586             :      * First initialize all variables declared in this block
    1587             :      */
    1588       69318 :     estate->err_text = gettext_noop("during statement block local variable initialization");
    1589             : 
    1590       80956 :     for (i = 0; i < block->n_initvars; i++)
    1591             :     {
    1592       11682 :         int         n = block->initvarnos[i];
    1593       11682 :         PLpgSQL_datum *datum = estate->datums[n];
    1594             : 
    1595             :         /*
    1596             :          * The set of dtypes handled here must match plpgsql_add_initdatums().
    1597             :          *
    1598             :          * Note that we currently don't support promise datums within blocks,
    1599             :          * only at a function's outermost scope, so we needn't handle those
    1600             :          * here.
    1601             :          */
    1602       11682 :         switch (datum->dtype)
    1603             :         {
    1604             :             case PLPGSQL_DTYPE_VAR:
    1605             :                 {
    1606        8942 :                     PLpgSQL_var *var = (PLpgSQL_var *) datum;
    1607             : 
    1608             :                     /*
    1609             :                      * Free any old value, in case re-entering block, and
    1610             :                      * initialize to NULL
    1611             :                      */
    1612        8942 :                     assign_simple_var(estate, var, (Datum) 0, true, false);
    1613             : 
    1614        8942 :                     if (var->default_val == NULL)
    1615             :                     {
    1616             :                         /*
    1617             :                          * If needed, give the datatype a chance to reject
    1618             :                          * NULLs, by assigning a NULL to the variable.  We
    1619             :                          * claim the value is of type UNKNOWN, not the var's
    1620             :                          * datatype, else coercion will be skipped.
    1621             :                          */
    1622        7908 :                         if (var->datatype->typtype == TYPTYPE_DOMAIN)
    1623          74 :                             exec_assign_value(estate,
    1624             :                                               (PLpgSQL_datum *) var,
    1625             :                                               (Datum) 0,
    1626             :                                               true,
    1627             :                                               UNKNOWNOID,
    1628             :                                               -1);
    1629             : 
    1630             :                         /* parser should have rejected NOT NULL */
    1631             :                         Assert(!var->notnull);
    1632             :                     }
    1633             :                     else
    1634             :                     {
    1635        1034 :                         exec_assign_expr(estate, (PLpgSQL_datum *) var,
    1636             :                                          var->default_val);
    1637             :                     }
    1638             :                 }
    1639        8916 :                 break;
    1640             : 
    1641             :             case PLPGSQL_DTYPE_REC:
    1642             :                 {
    1643        2740 :                     PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
    1644             : 
    1645             :                     /*
    1646             :                      * Deletion of any existing object will be handled during
    1647             :                      * the assignments below, and in some cases it's more
    1648             :                      * efficient for us not to get rid of it beforehand.
    1649             :                      */
    1650        2740 :                     if (rec->default_val == NULL)
    1651             :                     {
    1652             :                         /*
    1653             :                          * If needed, give the datatype a chance to reject
    1654             :                          * NULLs, by assigning a NULL to the variable.
    1655             :                          */
    1656        2704 :                         exec_move_row(estate, (PLpgSQL_variable *) rec,
    1657             :                                       NULL, NULL);
    1658             : 
    1659             :                         /* parser should have rejected NOT NULL */
    1660             :                         Assert(!rec->notnull);
    1661             :                     }
    1662             :                     else
    1663             :                     {
    1664          36 :                         exec_assign_expr(estate, (PLpgSQL_datum *) rec,
    1665             :                                          rec->default_val);
    1666             :                     }
    1667             :                 }
    1668        2722 :                 break;
    1669             : 
    1670             :             default:
    1671           0 :                 elog(ERROR, "unrecognized dtype: %d", datum->dtype);
    1672             :         }
    1673             :     }
    1674             : 
    1675       69274 :     if (block->exceptions)
    1676             :     {
    1677             :         /*
    1678             :          * Execute the statements in the block's body inside a sub-transaction
    1679             :          */
    1680        3940 :         MemoryContext oldcontext = CurrentMemoryContext;
    1681        3940 :         ResourceOwner oldowner = CurrentResourceOwner;
    1682        3940 :         ExprContext *old_eval_econtext = estate->eval_econtext;
    1683        3940 :         ErrorData  *save_cur_error = estate->cur_error;
    1684             :         MemoryContext stmt_mcontext;
    1685             : 
    1686        3940 :         estate->err_text = gettext_noop("during statement block entry");
    1687             : 
    1688             :         /*
    1689             :          * We will need a stmt_mcontext to hold the error data if an error
    1690             :          * occurs.  It seems best to force it to exist before entering the
    1691             :          * subtransaction, so that we reduce the risk of out-of-memory during
    1692             :          * error recovery, and because this greatly simplifies restoring the
    1693             :          * stmt_mcontext stack to the correct state after an error.  We can
    1694             :          * ameliorate the cost of this by allowing the called statements to
    1695             :          * use this mcontext too; so we don't push it down here.
    1696             :          */
    1697        3940 :         stmt_mcontext = get_stmt_mcontext(estate);
    1698             : 
    1699        3940 :         BeginInternalSubTransaction(NULL);
    1700             :         /* Want to run statements inside function's memory context */
    1701        3940 :         MemoryContextSwitchTo(oldcontext);
    1702             : 
    1703        3940 :         PG_TRY();
    1704             :         {
    1705             :             /*
    1706             :              * We need to run the block's statements with a new eval_econtext
    1707             :              * that belongs to the current subtransaction; if we try to use
    1708             :              * the outer econtext then ExprContext shutdown callbacks will be
    1709             :              * called at the wrong times.
    1710             :              */
    1711        3940 :             plpgsql_create_econtext(estate);
    1712             : 
    1713        3940 :             estate->err_text = NULL;
    1714             : 
    1715             :             /* Run the block's statements */
    1716        3940 :             rc = exec_stmts(estate, block->body);
    1717             : 
    1718        2952 :             estate->err_text = gettext_noop("during statement block exit");
    1719             : 
    1720             :             /*
    1721             :              * If the block ended with RETURN, we may need to copy the return
    1722             :              * value out of the subtransaction eval_context.  We can avoid a
    1723             :              * physical copy if the value happens to be a R/W expanded object.
    1724             :              */
    1725        3868 :             if (rc == PLPGSQL_RC_RETURN &&
    1726        1832 :                 !estate->retisset &&
    1727         916 :                 !estate->retisnull)
    1728             :             {
    1729             :                 int16       resTypLen;
    1730             :                 bool        resTypByVal;
    1731             : 
    1732         916 :                 get_typlenbyval(estate->rettype, &resTypLen, &resTypByVal);
    1733         916 :                 estate->retval = datumTransfer(estate->retval,
    1734             :                                                resTypByVal, resTypLen);
    1735             :             }
    1736             : 
    1737             :             /* Commit the inner transaction, return to outer xact context */
    1738        2952 :             ReleaseCurrentSubTransaction();
    1739        2952 :             MemoryContextSwitchTo(oldcontext);
    1740        2952 :             CurrentResourceOwner = oldowner;
    1741             : 
    1742             :             /* Assert that the stmt_mcontext stack is unchanged */
    1743             :             Assert(stmt_mcontext == estate->stmt_mcontext);
    1744             : 
    1745             :             /*
    1746             :              * Revert to outer eval_econtext.  (The inner one was
    1747             :              * automatically cleaned up during subxact exit.)
    1748             :              */
    1749        2952 :             estate->eval_econtext = old_eval_econtext;
    1750             :         }
    1751         988 :         PG_CATCH();
    1752             :         {
    1753             :             ErrorData  *edata;
    1754             :             ListCell   *e;
    1755             : 
    1756         988 :             estate->err_text = gettext_noop("during exception cleanup");
    1757             : 
    1758             :             /* Save error info in our stmt_mcontext */
    1759         988 :             MemoryContextSwitchTo(stmt_mcontext);
    1760         988 :             edata = CopyErrorData();
    1761         988 :             FlushErrorState();
    1762             : 
    1763             :             /* Abort the inner transaction */
    1764         988 :             RollbackAndReleaseCurrentSubTransaction();
    1765         988 :             MemoryContextSwitchTo(oldcontext);
    1766         988 :             CurrentResourceOwner = oldowner;
    1767             : 
    1768             :             /*
    1769             :              * Set up the stmt_mcontext stack as though we had restored our
    1770             :              * previous state and then done push_stmt_mcontext().  The push is
    1771             :              * needed so that statements in the exception handler won't
    1772             :              * clobber the error data that's in our stmt_mcontext.
    1773             :              */
    1774         988 :             estate->stmt_mcontext_parent = stmt_mcontext;
    1775         988 :             estate->stmt_mcontext = NULL;
    1776             : 
    1777             :             /*
    1778             :              * Now we can delete any nested stmt_mcontexts that might have
    1779             :              * been created as children of ours.  (Note: we do not immediately
    1780             :              * release any statement-lifespan data that might have been left
    1781             :              * behind in stmt_mcontext itself.  We could attempt that by doing
    1782             :              * a MemoryContextReset on it before collecting the error data
    1783             :              * above, but it seems too risky to do any significant amount of
    1784             :              * work before collecting the error.)
    1785             :              */
    1786         988 :             MemoryContextDeleteChildren(stmt_mcontext);
    1787             : 
    1788             :             /* Revert to outer eval_econtext */
    1789         988 :             estate->eval_econtext = old_eval_econtext;
    1790             : 
    1791             :             /*
    1792             :              * Must clean up the econtext too.  However, any tuple table made
    1793             :              * in the subxact will have been thrown away by SPI during subxact
    1794             :              * abort, so we don't need to (and mustn't try to) free the
    1795             :              * eval_tuptable.
    1796             :              */
    1797         988 :             estate->eval_tuptable = NULL;
    1798         988 :             exec_eval_cleanup(estate);
    1799             : 
    1800             :             /* Look for a matching exception handler */
    1801        1014 :             foreach(e, block->exceptions->exc_list)
    1802             :             {
    1803        1002 :                 PLpgSQL_exception *exception = (PLpgSQL_exception *) lfirst(e);
    1804             : 
    1805        1002 :                 if (exception_matches_conditions(edata, exception->conditions))
    1806             :                 {
    1807             :                     /*
    1808             :                      * Initialize the magic SQLSTATE and SQLERRM variables for
    1809             :                      * the exception block; this also frees values from any
    1810             :                      * prior use of the same exception. We needn't do this
    1811             :                      * until we have found a matching exception.
    1812             :                      */
    1813             :                     PLpgSQL_var *state_var;
    1814             :                     PLpgSQL_var *errm_var;
    1815             : 
    1816         976 :                     state_var = (PLpgSQL_var *)
    1817         976 :                         estate->datums[block->exceptions->sqlstate_varno];
    1818         976 :                     errm_var = (PLpgSQL_var *)
    1819         976 :                         estate->datums[block->exceptions->sqlerrm_varno];
    1820             : 
    1821         976 :                     assign_text_var(estate, state_var,
    1822         976 :                                     unpack_sql_state(edata->sqlerrcode));
    1823         976 :                     assign_text_var(estate, errm_var, edata->message);
    1824             : 
    1825             :                     /*
    1826             :                      * Also set up cur_error so the error data is accessible
    1827             :                      * inside the handler.
    1828             :                      */
    1829         976 :                     estate->cur_error = edata;
    1830             : 
    1831         976 :                     estate->err_text = NULL;
    1832             : 
    1833         976 :                     rc = exec_stmts(estate, exception->action);
    1834             : 
    1835         956 :                     break;
    1836             :                 }
    1837             :             }
    1838             : 
    1839             :             /*
    1840             :              * Restore previous state of cur_error, whether or not we executed
    1841             :              * a handler.  This is needed in case an error got thrown from
    1842             :              * some inner block's exception handler.
    1843             :              */
    1844         968 :             estate->cur_error = save_cur_error;
    1845             : 
    1846             :             /* If no match found, re-throw the error */
    1847         968 :             if (e == NULL)
    1848          12 :                 ReThrowError(edata);
    1849             : 
    1850             :             /* Restore stmt_mcontext stack and release the error data */
    1851         956 :             pop_stmt_mcontext(estate);
    1852         956 :             MemoryContextReset(stmt_mcontext);
    1853             :         }
    1854        3908 :         PG_END_TRY();
    1855             : 
    1856             :         Assert(save_cur_error == estate->cur_error);
    1857             :     }
    1858             :     else
    1859             :     {
    1860             :         /*
    1861             :          * Just execute the statements in the block's body
    1862             :          */
    1863       65334 :         estate->err_text = NULL;
    1864             : 
    1865       65334 :         rc = exec_stmts(estate, block->body);
    1866             :     }
    1867             : 
    1868       68636 :     estate->err_text = NULL;
    1869             : 
    1870             :     /*
    1871             :      * Handle the return code.  This is intentionally different from
    1872             :      * LOOP_RC_PROCESSING(): CONTINUE never matches a block, and EXIT matches
    1873             :      * a block only if there is a label match.
    1874             :      */
    1875       68636 :     switch (rc)
    1876             :     {
    1877             :         case PLPGSQL_RC_OK:
    1878             :         case PLPGSQL_RC_RETURN:
    1879             :         case PLPGSQL_RC_CONTINUE:
    1880       68624 :             return rc;
    1881             : 
    1882             :         case PLPGSQL_RC_EXIT:
    1883          12 :             if (estate->exitlabel == NULL)
    1884           4 :                 return PLPGSQL_RC_EXIT;
    1885           8 :             if (block->label == NULL)
    1886           2 :                 return PLPGSQL_RC_EXIT;
    1887           6 :             if (strcmp(block->label, estate->exitlabel) != 0)
    1888           2 :                 return PLPGSQL_RC_EXIT;
    1889           4 :             estate->exitlabel = NULL;
    1890           4 :             return PLPGSQL_RC_OK;
    1891             : 
    1892             :         default:
    1893           0 :             elog(ERROR, "unrecognized rc: %d", rc);
    1894             :     }
    1895             : 
    1896             :     return PLPGSQL_RC_OK;
    1897             : }
    1898             : 
    1899             : 
    1900             : /* ----------
    1901             :  * exec_stmts           Iterate over a list of statements
    1902             :  *              as long as their return code is OK
    1903             :  * ----------
    1904             :  */
    1905             : static int
    1906      162264 : exec_stmts(PLpgSQL_execstate *estate, List *stmts)
    1907             : {
    1908             :     ListCell   *s;
    1909             : 
    1910      162264 :     if (stmts == NIL)
    1911             :     {
    1912             :         /*
    1913             :          * Ensure we do a CHECK_FOR_INTERRUPTS() even though there is no
    1914             :          * statement.  This prevents hangup in a tight loop if, for instance,
    1915             :          * there is a LOOP construct with an empty body.
    1916             :          */
    1917       37472 :         CHECK_FOR_INTERRUPTS();
    1918       37472 :         return PLPGSQL_RC_OK;
    1919             :     }
    1920             : 
    1921      226164 :     foreach(s, stmts)
    1922             :     {
    1923      193422 :         PLpgSQL_stmt *stmt = (PLpgSQL_stmt *) lfirst(s);
    1924      193422 :         int         rc = exec_stmt(estate, stmt);
    1925             : 
    1926      191640 :         if (rc != PLPGSQL_RC_OK)
    1927       90268 :             return rc;
    1928             :     }
    1929             : 
    1930       32742 :     return PLPGSQL_RC_OK;
    1931             : }
    1932             : 
    1933             : 
    1934             : /* ----------
    1935             :  * exec_stmt            Distribute one statement to the statements
    1936             :  *              type specific execution function.
    1937             :  * ----------
    1938             :  */
    1939             : static int
    1940      258690 : exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
    1941             : {
    1942             :     PLpgSQL_stmt *save_estmt;
    1943      258690 :     int         rc = -1;
    1944             : 
    1945      258690 :     save_estmt = estate->err_stmt;
    1946      258690 :     estate->err_stmt = stmt;
    1947             : 
    1948             :     /* Let the plugin know that we are about to execute this statement */
    1949      258690 :     if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
    1950           0 :         ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
    1951             : 
    1952      258690 :     CHECK_FOR_INTERRUPTS();
    1953             : 
    1954      258690 :     switch (stmt->cmd_type)
    1955             :     {
    1956             :         case PLPGSQL_STMT_BLOCK:
    1957       69318 :             rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);
    1958       68636 :             break;
    1959             : 
    1960             :         case PLPGSQL_STMT_ASSIGN:
    1961       18366 :             rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
    1962       18208 :             break;
    1963             : 
    1964             :         case PLPGSQL_STMT_PERFORM:
    1965        2018 :             rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
    1966        1154 :             break;
    1967             : 
    1968             :         case PLPGSQL_STMT_CALL:
    1969          72 :             rc = exec_stmt_call(estate, (PLpgSQL_stmt_call *) stmt);
    1970          62 :             break;
    1971             : 
    1972             :         case PLPGSQL_STMT_GETDIAG:
    1973          66 :             rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
    1974          62 :             break;
    1975             : 
    1976             :         case PLPGSQL_STMT_IF:
    1977       68006 :             rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
    1978       67870 :             break;
    1979             : 
    1980             :         case PLPGSQL_STMT_CASE:
    1981          30 :             rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
    1982          24 :             break;
    1983             : 
    1984             :         case PLPGSQL_STMT_LOOP:
    1985          50 :             rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
    1986          50 :             break;
    1987             : 
    1988             :         case PLPGSQL_STMT_WHILE:
    1989         278 :             rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);
    1990         278 :             break;
    1991             : 
    1992             :         case PLPGSQL_STMT_FORI:
    1993         462 :             rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
    1994         448 :             break;
    1995             : 
    1996             :         case PLPGSQL_STMT_FORS:
    1997        1296 :             rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);
    1998        1260 :             break;
    1999             : 
    2000             :         case PLPGSQL_STMT_FORC:
    2001          24 :             rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt);
    2002          24 :             break;
    2003             : 
    2004             :         case PLPGSQL_STMT_FOREACH_A:
    2005          60 :             rc = exec_stmt_foreach_a(estate, (PLpgSQL_stmt_foreach_a *) stmt);
    2006          48 :             break;
    2007             : 
    2008             :         case PLPGSQL_STMT_EXIT:
    2009         822 :             rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
    2010         822 :             break;
    2011             : 
    2012             :         case PLPGSQL_STMT_RETURN:
    2013       64666 :             rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
    2014       64622 :             break;
    2015             : 
    2016             :         case PLPGSQL_STMT_RETURN_NEXT:
    2017        1594 :             rc = exec_stmt_return_next(estate, (PLpgSQL_stmt_return_next *) stmt);
    2018        1590 :             break;
    2019             : 
    2020             :         case PLPGSQL_STMT_RETURN_QUERY:
    2021         362 :             rc = exec_stmt_return_query(estate, (PLpgSQL_stmt_return_query *) stmt);
    2022         362 :             break;
    2023             : 
    2024             :         case PLPGSQL_STMT_RAISE:
    2025        6792 :             rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
    2026        6582 :             break;
    2027             : 
    2028             :         case PLPGSQL_STMT_ASSERT:
    2029          34 :             rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
    2030          18 :             break;
    2031             : 
    2032             :         case PLPGSQL_STMT_EXECSQL:
    2033        6966 :             rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
    2034        6868 :             break;
    2035             : 
    2036             :         case PLPGSQL_STMT_DYNEXECUTE:
    2037        6496 :             rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt);
    2038        6406 :             break;
    2039             : 
    2040             :         case PLPGSQL_STMT_DYNFORS:
    2041        2366 :             rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
    2042        2366 :             break;
    2043             : 
    2044             :         case PLPGSQL_STMT_OPEN:
    2045          84 :             rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt);
    2046          80 :             break;
    2047             : 
    2048             :         case PLPGSQL_STMT_FETCH:
    2049         228 :             rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt);
    2050         224 :             break;
    2051             : 
    2052             :         case PLPGSQL_STMT_CLOSE:
    2053          48 :             rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt);
    2054          48 :             break;
    2055             : 
    2056             :         case PLPGSQL_STMT_COMMIT:
    2057        4110 :             rc = exec_stmt_commit(estate, (PLpgSQL_stmt_commit *) stmt);
    2058        4088 :             break;
    2059             : 
    2060             :         case PLPGSQL_STMT_ROLLBACK:
    2061          72 :             rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt);
    2062          66 :             break;
    2063             : 
    2064             :         case PLPGSQL_STMT_SET:
    2065        4004 :             rc = exec_stmt_set(estate, (PLpgSQL_stmt_set *) stmt);
    2066        4000 :             break;
    2067             : 
    2068             :         default:
    2069           0 :             estate->err_stmt = save_estmt;
    2070           0 :             elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
    2071             :     }
    2072             : 
    2073             :     /* Let the plugin know that we have finished executing this statement */
    2074      256266 :     if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
    2075           0 :         ((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
    2076             : 
    2077      256266 :     estate->err_stmt = save_estmt;
    2078             : 
    2079      256266 :     return rc;
    2080             : }
    2081             : 
    2082             : 
    2083             : /* ----------
    2084             :  * exec_stmt_assign         Evaluate an expression and
    2085             :  *                  put the result into a variable.
    2086             :  * ----------
    2087             :  */
    2088             : static int
    2089       18366 : exec_stmt_assign(PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt)
    2090             : {
    2091             :     Assert(stmt->varno >= 0);
    2092             : 
    2093       18366 :     exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
    2094             : 
    2095       18208 :     return PLPGSQL_RC_OK;
    2096             : }
    2097             : 
    2098             : /* ----------
    2099             :  * exec_stmt_perform        Evaluate query and discard result (but set
    2100             :  *                          FOUND depending on whether at least one row
    2101             :  *                          was returned).
    2102             :  * ----------
    2103             :  */
    2104             : static int
    2105        2018 : exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
    2106             : {
    2107        2018 :     PLpgSQL_expr *expr = stmt->expr;
    2108             : 
    2109        2018 :     (void) exec_run_select(estate, expr, 0, NULL);
    2110        1154 :     exec_set_found(estate, (estate->eval_processed != 0));
    2111        1154 :     exec_eval_cleanup(estate);
    2112             : 
    2113        1154 :     return PLPGSQL_RC_OK;
    2114             : }
    2115             : 
    2116             : /*
    2117             :  * exec_stmt_call
    2118             :  */
    2119             : static int
    2120          72 : exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt)
    2121             : {
    2122          72 :     PLpgSQL_expr *expr = stmt->expr;
    2123             :     volatile LocalTransactionId before_lxid;
    2124             :     LocalTransactionId after_lxid;
    2125          72 :     volatile bool pushed_active_snap = false;
    2126             :     volatile int rc;
    2127             : 
    2128             :     /* PG_TRY to ensure we clear the plan link, if needed, on failure */
    2129          72 :     PG_TRY();
    2130             :     {
    2131          72 :         SPIPlanPtr  plan = expr->plan;
    2132             :         ParamListInfo paramLI;
    2133             : 
    2134          72 :         if (plan == NULL)
    2135             :         {
    2136             : 
    2137             :             /*
    2138             :              * Don't save the plan if not in atomic context.  Otherwise,
    2139             :              * transaction ends would cause errors about plancache leaks.
    2140             :              *
    2141             :              * XXX This would be fixable with some plancache/resowner surgery
    2142             :              * elsewhere, but for now we'll just work around this here.
    2143             :              */
    2144          62 :             exec_prepare_plan(estate, expr, 0, estate->atomic);
    2145             : 
    2146             :             /*
    2147             :              * The procedure call could end transactions, which would upset
    2148             :              * the snapshot management in SPI_execute*, so don't let it do it.
    2149             :              * Instead, we set the snapshots ourselves below.
    2150             :              */
    2151          62 :             plan = expr->plan;
    2152          62 :             plan->no_snapshots = true;
    2153             : 
    2154             :             /*
    2155             :              * Force target to be recalculated whenever the plan changes, in
    2156             :              * case the procedure's argument list has changed.
    2157             :              */
    2158          62 :             stmt->target = NULL;
    2159             :         }
    2160             : 
    2161             :         /*
    2162             :          * We construct a DTYPE_ROW datum representing the plpgsql variables
    2163             :          * associated with the procedure's output arguments.  Then we can use
    2164             :          * exec_move_row() to do the assignments.
    2165             :          */
    2166          72 :         if (stmt->is_call && stmt->target == NULL)
    2167             :         {
    2168             :             Node       *node;
    2169             :             FuncExpr   *funcexpr;
    2170             :             HeapTuple   func_tuple;
    2171             :             List       *funcargs;
    2172             :             Oid        *argtypes;
    2173             :             char      **argnames;
    2174             :             char       *argmodes;
    2175             :             MemoryContext oldcontext;
    2176             :             PLpgSQL_row *row;
    2177             :             int         nfields;
    2178             :             int         i;
    2179             :             ListCell   *lc;
    2180             : 
    2181             :             /*
    2182             :              * Get the parsed CallStmt, and look up the called procedure
    2183             :              */
    2184          60 :             node = linitial_node(Query,
    2185             :                                  ((CachedPlanSource *) linitial(plan->plancache_list))->query_list)->utilityStmt;
    2186          60 :             if (node == NULL || !IsA(node, CallStmt))
    2187           0 :                 elog(ERROR, "query for CALL statement is not a CallStmt");
    2188             : 
    2189          60 :             funcexpr = ((CallStmt *) node)->funcexpr;
    2190             : 
    2191          60 :             func_tuple = SearchSysCache1(PROCOID,
    2192          60 :                                          ObjectIdGetDatum(funcexpr->funcid));
    2193          60 :             if (!HeapTupleIsValid(func_tuple))
    2194           0 :                 elog(ERROR, "cache lookup failed for function %u",
    2195             :                      funcexpr->funcid);
    2196             : 
    2197             :             /*
    2198             :              * Extract function arguments, and expand any named-arg notation
    2199             :              */
    2200          60 :             funcargs = expand_function_arguments(funcexpr->args,
    2201             :                                                  funcexpr->funcresulttype,
    2202             :                                                  func_tuple);
    2203             : 
    2204             :             /*
    2205             :              * Get the argument names and modes, too
    2206             :              */
    2207          60 :             get_func_arg_info(func_tuple, &argtypes, &argnames, &argmodes);
    2208             : 
    2209          60 :             ReleaseSysCache(func_tuple);
    2210             : 
    2211             :             /*
    2212             :              * Begin constructing row Datum
    2213             :              */
    2214          60 :             oldcontext = MemoryContextSwitchTo(estate->func->fn_cxt);
    2215             : 
    2216          60 :             row = (PLpgSQL_row *) palloc0(sizeof(PLpgSQL_row));
    2217          60 :             row->dtype = PLPGSQL_DTYPE_ROW;
    2218          60 :             row->refname = "(unnamed row)";
    2219          60 :             row->lineno = -1;
    2220          60 :             row->varnos = (int *) palloc(sizeof(int) * list_length(funcargs));
    2221             : 
    2222          60 :             MemoryContextSwitchTo(oldcontext);
    2223             : 
    2224             :             /*
    2225             :              * Examine procedure's argument list.  Each output arg position
    2226             :              * should be an unadorned plpgsql variable (Datum), which we can
    2227             :              * insert into the row Datum.
    2228             :              */
    2229          60 :             nfields = 0;
    2230          60 :             i = 0;
    2231         190 :             foreach(lc, funcargs)
    2232             :             {
    2233         138 :                 Node       *n = lfirst(lc);
    2234             : 
    2235         256 :                 if (argmodes &&
    2236         144 :                     (argmodes[i] == PROARGMODE_INOUT ||
    2237          26 :                      argmodes[i] == PROARGMODE_OUT))
    2238             :                 {
    2239          92 :                     if (IsA(n, Param))
    2240             :                     {
    2241          84 :                         Param      *param = (Param *) n;
    2242             : 
    2243             :                         /* paramid is offset by 1 (see make_datum_param()) */
    2244          84 :                         row->varnos[nfields++] = param->paramid - 1;
    2245             :                     }
    2246             :                     else
    2247             :                     {
    2248             :                         /* report error using parameter name, if available */
    2249           8 :                         if (argnames && argnames[i] && argnames[i][0])
    2250           8 :                             ereport(ERROR,
    2251             :                                     (errcode(ERRCODE_SYNTAX_ERROR),
    2252             :                                      errmsg("procedure parameter \"%s\" is an output parameter but corresponding argument is not writable",
    2253             :                                             argnames[i])));
    2254             :                         else
    2255           0 :                             ereport(ERROR,
    2256             :                                     (errcode(ERRCODE_SYNTAX_ERROR),
    2257             :                                      errmsg("procedure parameter %d is an output parameter but corresponding argument is not writable",
    2258             :                                             i + 1)));
    2259             :                     }
    2260             :                 }
    2261         130 :                 i++;
    2262             :             }
    2263             : 
    2264          52 :             row->nfields = nfields;
    2265             : 
    2266          52 :             stmt->target = (PLpgSQL_variable *) row;
    2267             :         }
    2268             : 
    2269          64 :         paramLI = setup_param_list(estate, expr);
    2270             : 
    2271          64 :         before_lxid = MyProc->lxid;
    2272             : 
    2273             :         /*
    2274             :          * Set snapshot only for non-read-only procedures, similar to SPI
    2275             :          * behavior.
    2276             :          */
    2277          64 :         if (!estate->readonly_func)
    2278             :         {
    2279          64 :             PushActiveSnapshot(GetTransactionSnapshot());
    2280          64 :             pushed_active_snap = true;
    2281             :         }
    2282             : 
    2283          64 :         rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
    2284          64 :                                              estate->readonly_func, 0);
    2285             :     }
    2286          10 :     PG_CATCH();
    2287             :     {
    2288             :         /*
    2289             :          * If we aren't saving the plan, unset the pointer.  Note that it
    2290             :          * could have been unset already, in case of a recursive call.
    2291             :          */
    2292          10 :         if (expr->plan && !expr->plan->saved)
    2293           8 :             expr->plan = NULL;
    2294          10 :         PG_RE_THROW();
    2295             :     }
    2296          62 :     PG_END_TRY();
    2297             : 
    2298          62 :     if (expr->plan && !expr->plan->saved)
    2299          50 :         expr->plan = NULL;
    2300             : 
    2301          62 :     if (rc < 0)
    2302           0 :         elog(ERROR, "SPI_execute_plan_with_paramlist failed executing query \"%s\": %s",
    2303             :              expr->query, SPI_result_code_string(rc));
    2304             : 
    2305          62 :     after_lxid = MyProc->lxid;
    2306             : 
    2307          62 :     if (before_lxid == after_lxid)
    2308             :     {
    2309             :         /*
    2310             :          * If we are still in the same transaction after the call, pop the
    2311             :          * snapshot that we might have pushed.  (If it's a new transaction,
    2312             :          * then all the snapshots are gone already.)
    2313             :          */
    2314          56 :         if (pushed_active_snap)
    2315          56 :             PopActiveSnapshot();
    2316             :     }
    2317             :     else
    2318             :     {
    2319             :         /*
    2320             :          * If we are in a new transaction after the call, we need to reset
    2321             :          * some internal state.
    2322             :          */
    2323           6 :         estate->simple_eval_estate = NULL;
    2324           6 :         plpgsql_create_econtext(estate);
    2325             :     }
    2326             : 
    2327             :     /*
    2328             :      * Check result rowcount; if there's one row, assign procedure's output
    2329             :      * values back to the appropriate variables.
    2330             :      */
    2331          62 :     if (SPI_processed == 1)
    2332             :     {
    2333          46 :         SPITupleTable *tuptab = SPI_tuptable;
    2334             : 
    2335          46 :         if (!stmt->target)
    2336           0 :             elog(ERROR, "DO statement returned a row");
    2337             : 
    2338          46 :         exec_move_row(estate, stmt->target, tuptab->vals[0], tuptab->tupdesc);
    2339             :     }
    2340          16 :     else if (SPI_processed > 1)
    2341           0 :         elog(ERROR, "procedure call returned more than one row");
    2342             : 
    2343          62 :     exec_eval_cleanup(estate);
    2344          62 :     SPI_freetuptable(SPI_tuptable);
    2345             : 
    2346          62 :     return PLPGSQL_RC_OK;
    2347             : }
    2348             : 
    2349             : /* ----------
    2350             :  * exec_stmt_getdiag                    Put internal PG information into
    2351             :  *                                      specified variables.
    2352             :  * ----------
    2353             :  */
    2354             : static int
    2355          66 : exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
    2356             : {
    2357             :     ListCell   *lc;
    2358             : 
    2359             :     /*
    2360             :      * GET STACKED DIAGNOSTICS is only valid inside an exception handler.
    2361             :      *
    2362             :      * Note: we trust the grammar to have disallowed the relevant item kinds
    2363             :      * if not is_stacked, otherwise we'd dump core below.
    2364             :      */
    2365          66 :     if (stmt->is_stacked && estate->cur_error == NULL)
    2366           4 :         ereport(ERROR,
    2367             :                 (errcode(ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER),
    2368             :                  errmsg("GET STACKED DIAGNOSTICS cannot be used outside an exception handler")));
    2369             : 
    2370         172 :     foreach(lc, stmt->diag_items)
    2371             :     {
    2372         110 :         PLpgSQL_diag_item *diag_item = (PLpgSQL_diag_item *) lfirst(lc);
    2373         110 :         PLpgSQL_datum *var = estate->datums[diag_item->target];
    2374             : 
    2375         110 :         switch (diag_item->kind)
    2376             :         {
    2377             :             case PLPGSQL_GETDIAG_ROW_COUNT:
    2378          16 :                 exec_assign_value(estate, var,
    2379          16 :                                   UInt64GetDatum(estate->eval_processed),
    2380             :                                   false, INT8OID, -1);
    2381          16 :                 break;
    2382             : 
    2383             :             case PLPGSQL_GETDIAG_ERROR_CONTEXT:
    2384           4 :                 exec_assign_c_string(estate, var,
    2385           4 :                                      estate->cur_error->context);
    2386           4 :                 break;
    2387             : 
    2388             :             case PLPGSQL_GETDIAG_ERROR_DETAIL:
    2389           6 :                 exec_assign_c_string(estate, var,
    2390           6 :                                      estate->cur_error->detail);
    2391           6 :                 break;
    2392             : 
    2393             :             case PLPGSQL_GETDIAG_ERROR_HINT:
    2394           6 :                 exec_assign_c_string(estate, var,
    2395           6 :                                      estate->cur_error->hint);
    2396           6 :                 break;
    2397             : 
    2398             :             case PLPGSQL_GETDIAG_RETURNED_SQLSTATE:
    2399           6 :                 exec_assign_c_string(estate, var,
    2400           6 :                                      unpack_sql_state(estate->cur_error->sqlerrcode));
    2401           6 :                 break;
    2402             : 
    2403             :             case PLPGSQL_GETDIAG_COLUMN_NAME:
    2404           6 :                 exec_assign_c_string(estate, var,
    2405           6 :                                      estate->cur_error->column_name);
    2406           6 :                 break;
    2407             : 
    2408             :             case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
    2409           6 :                 exec_assign_c_string(estate, var,
    2410           6 :                                      estate->cur_error->constraint_name);
    2411           6 :                 break;
    2412             : 
    2413             :             case PLPGSQL_GETDIAG_DATATYPE_NAME:
    2414           6 :                 exec_assign_c_string(estate, var,
    2415           6 :                                      estate->cur_error->datatype_name);
    2416           6 :                 break;
    2417             : 
    2418             :             case PLPGSQL_GETDIAG_MESSAGE_TEXT:
    2419          10 :                 exec_assign_c_string(estate, var,
    2420          10 :                                      estate->cur_error->message);
    2421          10 :                 break;
    2422             : 
    2423             :             case PLPGSQL_GETDIAG_TABLE_NAME:
    2424           6 :                 exec_assign_c_string(estate, var,
    2425           6 :                                      estate->cur_error->table_name);
    2426           6 :                 break;
    2427             : 
    2428             :             case PLPGSQL_GETDIAG_SCHEMA_NAME:
    2429           6 :                 exec_assign_c_string(estate, var,
    2430           6 :                                      estate->cur_error->schema_name);
    2431           6 :                 break;
    2432             : 
    2433             :             case PLPGSQL_GETDIAG_CONTEXT:
    2434             :                 {
    2435             :                     char       *contextstackstr;
    2436             :                     MemoryContext oldcontext;
    2437             : 
    2438             :                     /* Use eval_mcontext for short-lived string */
    2439          32 :                     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    2440          32 :                     contextstackstr = GetErrorContextStack();
    2441          32 :                     MemoryContextSwitchTo(oldcontext);
    2442             : 
    2443          32 :                     exec_assign_c_string(estate, var, contextstackstr);
    2444             :                 }
    2445          32 :                 break;
    2446             : 
    2447             :             default:
    2448           0 :                 elog(ERROR, "unrecognized diagnostic item kind: %d",
    2449             :                      diag_item->kind);
    2450             :         }
    2451             :     }
    2452             : 
    2453          62 :     exec_eval_cleanup(estate);
    2454             : 
    2455          62 :     return PLPGSQL_RC_OK;
    2456             : }
    2457             : 
    2458             : /* ----------
    2459             :  * exec_stmt_if             Evaluate a bool expression and
    2460             :  *                  execute the true or false body
    2461             :  *                  conditionally.
    2462             :  * ----------
    2463             :  */
    2464             : static int
    2465       68006 : exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
    2466             : {
    2467             :     bool        value;
    2468             :     bool        isnull;
    2469             :     ListCell   *lc;
    2470             : 
    2471       68006 :     value = exec_eval_boolean(estate, stmt->cond, &isnull);
    2472       68006 :     exec_eval_cleanup(estate);
    2473       68006 :     if (!isnull && value)
    2474       28172 :         return exec_stmts(estate, stmt->then_body);
    2475             : 
    2476       39838 :     foreach(lc, stmt->elsif_list)
    2477             :     {
    2478         140 :         PLpgSQL_if_elsif *elif = (PLpgSQL_if_elsif *) lfirst(lc);
    2479             : 
    2480         140 :         value = exec_eval_boolean(estate, elif->cond, &isnull);
    2481         140 :         exec_eval_cleanup(estate);
    2482         140 :         if (!isnull && value)
    2483         136 :             return exec_stmts(estate, elif->stmts);
    2484             :     }
    2485             : 
    2486       39698 :     return exec_stmts(estate, stmt->else_body);
    2487             : }
    2488             : 
    2489             : 
    2490             : /*-----------
    2491             :  * exec_stmt_case
    2492             :  *-----------
    2493             :  */
    2494             : static int
    2495          30 : exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
    2496             : {
    2497          30 :     PLpgSQL_var *t_var = NULL;
    2498             :     bool        isnull;
    2499             :     ListCell   *l;
    2500             : 
    2501          30 :     if (stmt->t_expr != NULL)
    2502             :     {
    2503             :         /* simple case */
    2504             :         Datum       t_val;
    2505             :         Oid         t_typoid;
    2506             :         int32       t_typmod;
    2507             : 
    2508          22 :         t_val = exec_eval_expr(estate, stmt->t_expr,
    2509             :                                &isnull, &t_typoid, &t_typmod);
    2510             : 
    2511          22 :         t_var = (PLpgSQL_var *) estate->datums[stmt->t_varno];
    2512             : 
    2513             :         /*
    2514             :          * When expected datatype is different from real, change it. Note that
    2515             :          * what we're modifying here is an execution copy of the datum, so
    2516             :          * this doesn't affect the originally stored function parse tree. (In
    2517             :          * theory, if the expression datatype keeps changing during execution,
    2518             :          * this could cause a function-lifespan memory leak.  Doesn't seem
    2519             :          * worth worrying about though.)
    2520             :          */
    2521          22 :         if (t_var->datatype->typoid != t_typoid ||
    2522           0 :             t_var->datatype->atttypmod != t_typmod)
    2523          22 :             t_var->datatype = plpgsql_build_datatype(t_typoid,
    2524             :                                                      t_typmod,
    2525          22 :                                                      estate->func->fn_input_collation,
    2526             :                                                      NULL);
    2527             : 
    2528             :         /* now we can assign to the variable */
    2529          22 :         exec_assign_value(estate,
    2530             :                           (PLpgSQL_datum *) t_var,
    2531             :                           t_val,
    2532             :                           isnull,
    2533             :                           t_typoid,
    2534             :                           t_typmod);
    2535             : 
    2536          22 :         exec_eval_cleanup(estate);
    2537             :     }
    2538             : 
    2539             :     /* Now search for a successful WHEN clause */
    2540         106 :     foreach(l, stmt->case_when_list)
    2541             :     {
    2542          96 :         PLpgSQL_case_when *cwt = (PLpgSQL_case_when *) lfirst(l);
    2543             :         bool        value;
    2544             : 
    2545          96 :         value = exec_eval_boolean(estate, cwt->expr, &isnull);
    2546          96 :         exec_eval_cleanup(estate);
    2547          96 :         if (!isnull && value)
    2548             :         {
    2549             :             /* Found it */
    2550             : 
    2551             :             /* We can now discard any value we had for the temp variable */
    2552          20 :             if (t_var != NULL)
    2553          16 :                 assign_simple_var(estate, t_var, (Datum) 0, true, false);
    2554             : 
    2555             :             /* Evaluate the statement(s), and we're done */
    2556          20 :             return exec_stmts(estate, cwt->stmts);
    2557             :         }
    2558             :     }
    2559             : 
    2560             :     /* We can now discard any value we had for the temp variable */
    2561          10 :     if (t_var != NULL)
    2562           6 :         assign_simple_var(estate, t_var, (Datum) 0, true, false);
    2563             : 
    2564             :     /* SQL2003 mandates this error if there was no ELSE clause */
    2565          10 :     if (!stmt->have_else)
    2566           6 :         ereport(ERROR,
    2567             :                 (errcode(ERRCODE_CASE_NOT_FOUND),
    2568             :                  errmsg("case not found"),
    2569             :                  errhint("CASE statement is missing ELSE part.")));
    2570             : 
    2571             :     /* Evaluate the ELSE statements, and we're done */
    2572           4 :     return exec_stmts(estate, stmt->else_stmts);
    2573             : }
    2574             : 
    2575             : 
    2576             : /* ----------
    2577             :  * exec_stmt_loop           Loop over statements until
    2578             :  *                  an exit occurs.
    2579             :  * ----------
    2580             :  */
    2581             : static int
    2582          50 : exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
    2583             : {
    2584          50 :     int         rc = PLPGSQL_RC_OK;
    2585             : 
    2586             :     for (;;)
    2587             :     {
    2588         806 :         rc = exec_stmts(estate, stmt->body);
    2589             : 
    2590         428 :         LOOP_RC_PROCESSING(stmt->label, break);
    2591             :     }
    2592             : 
    2593          50 :     return rc;
    2594             : }
    2595             : 
    2596             : 
    2597             : /* ----------
    2598             :  * exec_stmt_while          Loop over statements as long
    2599             :  *                  as an expression evaluates to
    2600             :  *                  true or an exit occurs.
    2601             :  * ----------
    2602             :  */
    2603             : static int
    2604         278 : exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
    2605             : {
    2606         278 :     int         rc = PLPGSQL_RC_OK;
    2607             : 
    2608             :     for (;;)
    2609        1972 :     {
    2610             :         bool        value;
    2611             :         bool        isnull;
    2612             : 
    2613        2250 :         value = exec_eval_boolean(estate, stmt->cond, &isnull);
    2614        2250 :         exec_eval_cleanup(estate);
    2615             : 
    2616        2250 :         if (isnull || !value)
    2617             :             break;
    2618             : 
    2619        1992 :         rc = exec_stmts(estate, stmt->body);
    2620             : 
    2621        1992 :         LOOP_RC_PROCESSING(stmt->label, break);
    2622             :     }
    2623             : 
    2624         278 :     return rc;
    2625             : }
    2626             : 
    2627             : 
    2628             : /* ----------
    2629             :  * exec_stmt_fori           Iterate an integer variable
    2630             :  *                  from a lower to an upper value
    2631             :  *                  incrementing or decrementing by the BY value
    2632             :  * ----------
    2633             :  */
    2634             : static int
    2635         462 : exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
    2636             : {
    2637             :     PLpgSQL_var *var;
    2638             :     Datum       value;
    2639             :     bool        isnull;
    2640             :     Oid         valtype;
    2641             :     int32       valtypmod;
    2642             :     int32       loop_value;
    2643             :     int32       end_value;
    2644             :     int32       step_value;
    2645         462 :     bool        found = false;
    2646         462 :     int         rc = PLPGSQL_RC_OK;
    2647             : 
    2648         462 :     var = (PLpgSQL_var *) (estate->datums[stmt->var->dno]);
    2649             : 
    2650             :     /*
    2651             :      * Get the value of the lower bound
    2652             :      */
    2653         462 :     value = exec_eval_expr(estate, stmt->lower,
    2654             :                            &isnull, &valtype, &valtypmod);
    2655         924 :     value = exec_cast_value(estate, value, &isnull,
    2656             :                             valtype, valtypmod,
    2657         462 :                             var->datatype->typoid,
    2658         462 :                             var->datatype->atttypmod);
    2659         462 :     if (isnull)
    2660           0 :         ereport(ERROR,
    2661             :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    2662             :                  errmsg("lower bound of FOR loop cannot be null")));
    2663         462 :     loop_value = DatumGetInt32(value);
    2664         462 :     exec_eval_cleanup(estate);
    2665             : 
    2666             :     /*
    2667             :      * Get the value of the upper bound
    2668             :      */
    2669         462 :     value = exec_eval_expr(estate, stmt->upper,
    2670             :                            &isnull, &valtype, &valtypmod);
    2671         924 :     value = exec_cast_value(estate, value, &isnull,
    2672             :                             valtype, valtypmod,
    2673         462 :                             var->datatype->typoid,
    2674         462 :                             var->datatype->atttypmod);
    2675         462 :     if (isnull)
    2676           0 :         ereport(ERROR,
    2677             :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    2678             :                  errmsg("upper bound of FOR loop cannot be null")));
    2679         462 :     end_value = DatumGetInt32(value);
    2680         462 :     exec_eval_cleanup(estate);
    2681             : 
    2682             :     /*
    2683             :      * Get the step value
    2684             :      */
    2685         462 :     if (stmt->step)
    2686             :     {
    2687          18 :         value = exec_eval_expr(estate, stmt->step,
    2688             :                                &isnull, &valtype, &valtypmod);
    2689          36 :         value = exec_cast_value(estate, value, &isnull,
    2690             :                                 valtype, valtypmod,
    2691          18 :                                 var->datatype->typoid,
    2692          18 :                                 var->datatype->atttypmod);
    2693          18 :         if (isnull)
    2694           0 :             ereport(ERROR,
    2695             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    2696             :                      errmsg("BY value of FOR loop cannot be null")));
    2697          18 :         step_value = DatumGetInt32(value);
    2698          18 :         exec_eval_cleanup(estate);
    2699          18 :         if (step_value <= 0)
    2700           6 :             ereport(ERROR,
    2701             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    2702             :                      errmsg("BY value of FOR loop must be greater than zero")));
    2703             :     }
    2704             :     else
    2705         444 :         step_value = 1;
    2706             : 
    2707             :     /*
    2708             :      * Now do the loop
    2709             :      */
    2710             :     for (;;)
    2711             :     {
    2712             :         /*
    2713             :          * Check against upper bound
    2714             :          */
    2715       14668 :         if (stmt->reverse)
    2716             :         {
    2717          16 :             if (loop_value < end_value)
    2718           2 :                 break;
    2719             :         }
    2720             :         else
    2721             :         {
    2722        7546 :             if (loop_value > end_value)
    2723         428 :                 break;
    2724             :         }
    2725             : 
    2726        7132 :         found = true;           /* looped at least once */
    2727             : 
    2728             :         /*
    2729             :          * Assign current value to loop var
    2730             :          */
    2731        7132 :         assign_simple_var(estate, var, Int32GetDatum(loop_value), false, false);
    2732             : 
    2733             :         /*
    2734             :          * Execute the statements
    2735             :          */
    2736        7132 :         rc = exec_stmts(estate, stmt->body);
    2737             : 
    2738        7124 :         LOOP_RC_PROCESSING(stmt->label, break);
    2739             : 
    2740             :         /*
    2741             :          * Increase/decrease loop value, unless it would overflow, in which
    2742             :          * case exit the loop.
    2743             :          */
    2744        7110 :         if (stmt->reverse)
    2745             :         {
    2746          14 :             if (loop_value < (PG_INT32_MIN + step_value))
    2747           2 :                 break;
    2748          12 :             loop_value -= step_value;
    2749             :         }
    2750             :         else
    2751             :         {
    2752        7096 :             if (loop_value > (PG_INT32_MAX - step_value))
    2753           2 :                 break;
    2754        7094 :             loop_value += step_value;
    2755             :         }
    2756             :     }
    2757             : 
    2758             :     /*
    2759             :      * Set the FOUND variable to indicate the result of executing the loop
    2760             :      * (namely, whether we looped one or more times). This must be set here so
    2761             :      * that it does not interfere with the value of the FOUND variable inside
    2762             :      * the loop processing itself.
    2763             :      */
    2764         448 :     exec_set_found(estate, found);
    2765             : 
    2766         448 :     return rc;
    2767             : }
    2768             : 
    2769             : 
    2770             : /* ----------
    2771             :  * exec_stmt_fors           Execute a query, assign each
    2772             :  *                  tuple to a record or row and
    2773             :  *                  execute a group of statements
    2774             :  *                  for it.
    2775             :  * ----------
    2776             :  */
    2777             : static int
    2778        1296 : exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
    2779             : {
    2780             :     Portal      portal;
    2781             :     int         rc;
    2782             : 
    2783             :     /*
    2784             :      * Open the implicit cursor for the statement using exec_run_select
    2785             :      */
    2786        1296 :     exec_run_select(estate, stmt->query, 0, &portal);
    2787             : 
    2788             :     /*
    2789             :      * Execute the loop
    2790             :      */
    2791        1288 :     rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, true);
    2792             : 
    2793             :     /*
    2794             :      * Close the implicit cursor
    2795             :      */
    2796        1260 :     SPI_cursor_close(portal);
    2797             : 
    2798        1260 :     return rc;
    2799             : }
    2800             : 
    2801             : 
    2802             : /* ----------
    2803             :  * exec_stmt_forc           Execute a loop for each row from a cursor.
    2804             :  * ----------
    2805             :  */
    2806             : static int
    2807          24 : exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
    2808             : {
    2809             :     PLpgSQL_var *curvar;
    2810          24 :     MemoryContext stmt_mcontext = NULL;
    2811          24 :     char       *curname = NULL;
    2812             :     PLpgSQL_expr *query;
    2813             :     ParamListInfo paramLI;
    2814             :     Portal      portal;
    2815             :     int         rc;
    2816             : 
    2817             :     /* ----------
    2818             :      * Get the cursor variable and if it has an assigned name, check
    2819             :      * that it's not in use currently.
    2820             :      * ----------
    2821             :      */
    2822          24 :     curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
    2823          24 :     if (!curvar->isnull)
    2824             :     {
    2825             :         MemoryContext oldcontext;
    2826             : 
    2827             :         /* We only need stmt_mcontext to hold the cursor name string */
    2828          20 :         stmt_mcontext = get_stmt_mcontext(estate);
    2829          20 :         oldcontext = MemoryContextSwitchTo(stmt_mcontext);
    2830          20 :         curname = TextDatumGetCString(curvar->value);
    2831          20 :         MemoryContextSwitchTo(oldcontext);
    2832             : 
    2833          20 :         if (SPI_cursor_find(curname) != NULL)
    2834           0 :             ereport(ERROR,
    2835             :                     (errcode(ERRCODE_DUPLICATE_CURSOR),
    2836             :                      errmsg("cursor \"%s\" already in use", curname)));
    2837             :     }
    2838             : 
    2839             :     /* ----------
    2840             :      * Open the cursor just like an OPEN command
    2841             :      *
    2842             :      * Note: parser should already have checked that statement supplies
    2843             :      * args iff cursor needs them, but we check again to be safe.
    2844             :      * ----------
    2845             :      */
    2846          24 :     if (stmt->argquery != NULL)
    2847             :     {
    2848             :         /* ----------
    2849             :          * OPEN CURSOR with args.  We fake a SELECT ... INTO ...
    2850             :          * statement to evaluate the args and put 'em into the
    2851             :          * internal row.
    2852             :          * ----------
    2853             :          */
    2854             :         PLpgSQL_stmt_execsql set_args;
    2855             : 
    2856           8 :         if (curvar->cursor_explicit_argrow < 0)
    2857           0 :             ereport(ERROR,
    2858             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    2859             :                      errmsg("arguments given for cursor without arguments")));
    2860             : 
    2861           8 :         memset(&set_args, 0, sizeof(set_args));
    2862           8 :         set_args.cmd_type = PLPGSQL_STMT_EXECSQL;
    2863           8 :         set_args.lineno = stmt->lineno;
    2864           8 :         set_args.sqlstmt = stmt->argquery;
    2865           8 :         set_args.into = true;
    2866             :         /* XXX historically this has not been STRICT */
    2867           8 :         set_args.target = (PLpgSQL_variable *)
    2868           8 :             (estate->datums[curvar->cursor_explicit_argrow]);
    2869             : 
    2870           8 :         if (exec_stmt_execsql(estate, &set_args) != PLPGSQL_RC_OK)
    2871           0 :             elog(ERROR, "open cursor failed during argument processing");
    2872             :     }
    2873             :     else
    2874             :     {
    2875          16 :         if (curvar->cursor_explicit_argrow >= 0)
    2876           0 :             ereport(ERROR,
    2877             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    2878             :                      errmsg("arguments required for cursor")));
    2879             :     }
    2880             : 
    2881          24 :     query = curvar->cursor_explicit_expr;
    2882             :     Assert(query);
    2883             : 
    2884          24 :     if (query->plan == NULL)
    2885          12 :         exec_prepare_plan(estate, query, curvar->cursor_options, true);
    2886             : 
    2887             :     /*
    2888             :      * Set up ParamListInfo for this query
    2889             :      */
    2890          24 :     paramLI = setup_param_list(estate, query);
    2891             : 
    2892             :     /*
    2893             :      * Open the cursor (the paramlist will get copied into the portal)
    2894             :      */
    2895          24 :     portal = SPI_cursor_open_with_paramlist(curname, query->plan,
    2896             :                                             paramLI,
    2897          24 :                                             estate->readonly_func);
    2898          24 :     if (portal == NULL)
    2899           0 :         elog(ERROR, "could not open cursor: %s",
    2900             :              SPI_result_code_string(SPI_result));
    2901             : 
    2902             :     /*
    2903             :      * If cursor variable was NULL, store the generated portal name in it
    2904             :      */
    2905          24 :     if (curname == NULL)
    2906           4 :         assign_text_var(estate, curvar, portal->name);
    2907             : 
    2908             :     /*
    2909             :      * Clean up before entering exec_for_query
    2910             :      */
    2911          24 :     exec_eval_cleanup(estate);
    2912          24 :     if (stmt_mcontext)
    2913          20 :         MemoryContextReset(stmt_mcontext);
    2914             : 
    2915             :     /*
    2916             :      * Execute the loop.  We can't prefetch because the cursor is accessible
    2917             :      * to the user, for instance via UPDATE WHERE CURRENT OF within the loop.
    2918             :      */
    2919          24 :     rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, false);
    2920             : 
    2921             :     /* ----------
    2922             :      * Close portal, and restore cursor variable if it was initially NULL.
    2923             :      * ----------
    2924             :      */
    2925          24 :     SPI_cursor_close(portal);
    2926             : 
    2927          24 :     if (curname == NULL)
    2928           4 :         assign_simple_var(estate, curvar, (Datum) 0, true, false);
    2929             : 
    2930          24 :     return rc;
    2931             : }
    2932             : 
    2933             : 
    2934             : /* ----------
    2935             :  * exec_stmt_foreach_a          Loop over elements or slices of an array
    2936             :  *
    2937             :  * When looping over elements, the loop variable is the same type that the
    2938             :  * array stores (eg: integer), when looping through slices, the loop variable
    2939             :  * is an array of size and dimensions to match the size of the slice.
    2940             :  * ----------
    2941             :  */
    2942             : static int
    2943          60 : exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
    2944             : {
    2945             :     ArrayType  *arr;
    2946             :     Oid         arrtype;
    2947             :     int32       arrtypmod;
    2948             :     PLpgSQL_datum *loop_var;
    2949             :     Oid         loop_var_elem_type;
    2950          60 :     bool        found = false;
    2951          60 :     int         rc = PLPGSQL_RC_OK;
    2952             :     MemoryContext stmt_mcontext;
    2953             :     MemoryContext oldcontext;
    2954             :     ArrayIterator array_iterator;
    2955             :     Oid         iterator_result_type;
    2956             :     int32       iterator_result_typmod;
    2957             :     Datum       value;
    2958             :     bool        isnull;
    2959             : 
    2960             :     /* get the value of the array expression */
    2961          60 :     value = exec_eval_expr(estate, stmt->expr, &isnull, &arrtype, &arrtypmod);
    2962          60 :     if (isnull)
    2963           0 :         ereport(ERROR,
    2964             :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    2965             :                  errmsg("FOREACH expression must not be null")));
    2966             : 
    2967             :     /*
    2968             :      * Do as much as possible of the code below in stmt_mcontext, to avoid any
    2969             :      * leaks from called subroutines.  We need a private stmt_mcontext since
    2970             :      * we'll be calling arbitrary statement code.
    2971             :      */
    2972          60 :     stmt_mcontext = get_stmt_mcontext(estate);
    2973          60 :     push_stmt_mcontext(estate);
    2974          60 :     oldcontext = MemoryContextSwitchTo(stmt_mcontext);
    2975             : 
    2976             :     /* check the type of the expression - must be an array */
    2977          60 :     if (!OidIsValid(get_element_type(arrtype)))
    2978           0 :         ereport(ERROR,
    2979             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    2980             :                  errmsg("FOREACH expression must yield an array, not type %s",
    2981             :                         format_type_be(arrtype))));
    2982             : 
    2983             :     /*
    2984             :      * We must copy the array into stmt_mcontext, else it will disappear in
    2985             :      * exec_eval_cleanup.  This is annoying, but cleanup will certainly happen
    2986             :      * while running the loop body, so we have little choice.
    2987             :      */
    2988          60 :     arr = DatumGetArrayTypePCopy(value);
    2989             : 
    2990             :     /* Clean up any leftover temporary memory */
    2991          60 :     exec_eval_cleanup(estate);
    2992             : 
    2993             :     /* Slice dimension must be less than or equal to array dimension */
    2994          60 :     if (stmt->slice < 0 || stmt->slice > ARR_NDIM(arr))
    2995           4 :         ereport(ERROR,
    2996             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
    2997             :                  errmsg("slice dimension (%d) is out of the valid range 0..%d",
    2998             :                         stmt->slice, ARR_NDIM(arr))));
    2999             : 
    3000             :     /* Set up the loop variable and see if it is of an array type */
    3001          56 :     loop_var = estate->datums[stmt->varno];
    3002         104 :     if (loop_var->dtype == PLPGSQL_DTYPE_REC ||
    3003          48 :         loop_var->dtype == PLPGSQL_DTYPE_ROW)
    3004             :     {
    3005             :         /*
    3006             :          * Record/row variable is certainly not of array type, and might not
    3007             :          * be initialized at all yet, so don't try to get its type
    3008             :          */
    3009          16 :         loop_var_elem_type = InvalidOid;
    3010             :     }
    3011             :     else
    3012          40 :         loop_var_elem_type = get_element_type(plpgsql_exec_get_datum_type(estate,
    3013             :                                                                           loop_var));
    3014             : 
    3015             :     /*
    3016             :      * Sanity-check the loop variable type.  We don't try very hard here, and
    3017             :      * should not be too picky since it's possible that exec_assign_value can
    3018             :      * coerce values of different types.  But it seems worthwhile to complain
    3019             :      * if the array-ness of the loop variable is not right.
    3020             :      */
    3021          56 :     if (stmt->slice > 0 && loop_var_elem_type == InvalidOid)
    3022           8 :         ereport(ERROR,
    3023             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3024             :                  errmsg("FOREACH ... SLICE loop variable must be of an array type")));
    3025          48 :     if (stmt->slice == 0 && loop_var_elem_type != InvalidOid)
    3026           0 :         ereport(ERROR,
    3027             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3028             :                  errmsg("FOREACH loop variable must not be of an array type")));
    3029             : 
    3030             :     /* Create an iterator to step through the array */
    3031          48 :     array_iterator = array_create_iterator(arr, stmt->slice, NULL);
    3032             : 
    3033             :     /* Identify iterator result type */
    3034          48 :     if (stmt->slice > 0)
    3035             :     {
    3036             :         /* When slicing, nominal type of result is same as array type */
    3037          24 :         iterator_result_type = arrtype;
    3038          24 :         iterator_result_typmod = arrtypmod;
    3039             :     }
    3040             :     else
    3041             :     {
    3042             :         /* Without slicing, results are individual array elements */
    3043          24 :         iterator_result_type = ARR_ELEMTYPE(arr);
    3044          24 :         iterator_result_typmod = arrtypmod;
    3045             :     }
    3046             : 
    3047             :     /* Iterate over the array elements or slices */
    3048         220 :     while (array_iterate(array_iterator, &value, &isnull))
    3049             :     {
    3050         124 :         found = true;           /* looped at least once */
    3051             : 
    3052             :         /* exec_assign_value and exec_stmts must run in the main context */
    3053         124 :         MemoryContextSwitchTo(oldcontext);
    3054             : 
    3055             :         /* Assign current element/slice to the loop variable */
    3056         124 :         exec_assign_value(estate, loop_var, value, isnull,
    3057             :                           iterator_result_type, iterator_result_typmod);
    3058             : 
    3059             :         /* In slice case, value is temporary; must free it to avoid leakage */
    3060         124 :         if (stmt->slice > 0)
    3061          36 :             pfree(DatumGetPointer(value));
    3062             : 
    3063             :         /*
    3064             :          * Execute the statements
    3065             :          */
    3066         124 :         rc = exec_stmts(estate, stmt->body);
    3067             : 
    3068         124 :         LOOP_RC_PROCESSING(stmt->label, break);
    3069             : 
    3070         124 :         MemoryContextSwitchTo(stmt_mcontext);
    3071             :     }
    3072             : 
    3073             :     /* Restore memory context state */
    3074          48 :     MemoryContextSwitchTo(oldcontext);
    3075          48 :     pop_stmt_mcontext(estate);
    3076             : 
    3077             :     /* Release temporary memory, including the array value */
    3078          48 :     MemoryContextReset(stmt_mcontext);
    3079             : 
    3080             :     /*
    3081             :      * Set the FOUND variable to indicate the result of executing the loop
    3082             :      * (namely, whether we looped one or more times). This must be set here so
    3083             :      * that it does not interfere with the value of the FOUND variable inside
    3084             :      * the loop processing itself.
    3085             :      */
    3086          48 :     exec_set_found(estate, found);
    3087             : 
    3088          48 :     return rc;
    3089             : }
    3090             : 
    3091             : 
    3092             : /* ----------
    3093             :  * exec_stmt_exit           Implements EXIT and CONTINUE
    3094             :  *
    3095             :  * This begins the process of exiting / restarting a loop.
    3096             :  * ----------
    3097             :  */
    3098             : static int
    3099         822 : exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
    3100             : {
    3101             :     /*
    3102             :      * If the exit / continue has a condition, evaluate it
    3103             :      */
    3104         822 :     if (stmt->cond != NULL)
    3105             :     {
    3106             :         bool        value;
    3107             :         bool        isnull;
    3108             : 
    3109         638 :         value = exec_eval_boolean(estate, stmt->cond, &isnull);
    3110         638 :         exec_eval_cleanup(estate);
    3111         638 :         if (isnull || value == false)
    3112         488 :             return PLPGSQL_RC_OK;
    3113             :     }
    3114             : 
    3115         334 :     estate->exitlabel = stmt->label;
    3116         334 :     if (stmt->is_exit)
    3117          48 :         return PLPGSQL_RC_EXIT;
    3118             :     else
    3119         286 :         return PLPGSQL_RC_CONTINUE;
    3120             : }
    3121             : 
    3122             : 
    3123             : /* ----------
    3124             :  * exec_stmt_return         Evaluate an expression and start
    3125             :  *                  returning from the function.
    3126             :  *
    3127             :  * Note: The result may be in the eval_mcontext.  Therefore, we must not
    3128             :  * do exec_eval_cleanup while unwinding the control stack.
    3129             :  * ----------
    3130             :  */
    3131             : static int
    3132       64666 : exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
    3133             : {
    3134             :     /*
    3135             :      * If processing a set-returning PL/pgSQL function, the final RETURN
    3136             :      * indicates that the function is finished producing tuples.  The rest of
    3137             :      * the work will be done at the top level.
    3138             :      */
    3139       64666 :     if (estate->retisset)
    3140         688 :         return PLPGSQL_RC_RETURN;
    3141             : 
    3142             :     /* initialize for null result */
    3143       63978 :     estate->retval = (Datum) 0;
    3144       63978 :     estate->retisnull = true;
    3145       63978 :     estate->rettype = InvalidOid;
    3146             : 
    3147             :     /*
    3148             :      * Special case path when the RETURN expression is a simple variable
    3149             :      * reference; in particular, this path is always taken in functions with
    3150             :      * one or more OUT parameters.
    3151             :      *
    3152             :      * This special case is especially efficient for returning variables that
    3153             :      * have R/W expanded values: we can put the R/W pointer directly into
    3154             :      * estate->retval, leading to transferring the value to the caller's
    3155             :      * context cheaply.  If we went through exec_eval_expr we'd end up with a
    3156             :      * R/O pointer.  It's okay to skip MakeExpandedObjectReadOnly here since
    3157             :      * we know we won't need the variable's value within the function anymore.
    3158             :      */
    3159       63978 :     if (stmt->retvarno >= 0)
    3160             :     {
    3161       28748 :         PLpgSQL_datum *retvar = estate->datums[stmt->retvarno];
    3162             : 
    3163       28748 :         switch (retvar->dtype)
    3164             :         {
    3165             :             case PLPGSQL_DTYPE_PROMISE:
    3166             :                 /* fulfill promise if needed, then handle like regular var */
    3167           0 :                 plpgsql_fulfill_promise(estate, (PLpgSQL_var *) retvar);
    3168             : 
    3169             :                 /* FALL THRU */
    3170             : 
    3171             :             case PLPGSQL_DTYPE_VAR:
    3172             :                 {
    3173       20490 :                     PLpgSQL_var *var = (PLpgSQL_var *) retvar;
    3174             : 
    3175       20490 :                     estate->retval = var->value;
    3176       20490 :                     estate->retisnull = var->isnull;
    3177       20490 :                     estate->rettype = var->datatype->typoid;
    3178             : 
    3179             :                     /*
    3180             :                      * A PLpgSQL_var could not be of composite type, so
    3181             :                      * conversion must fail if retistuple.  We throw a custom
    3182             :                      * error mainly for consistency with historical behavior.
    3183             :                      * For the same reason, we don't throw error if the result
    3184             :                      * is NULL.  (Note that plpgsql_exec_trigger assumes that
    3185             :                      * any non-null result has been verified to be composite.)
    3186             :                      */
    3187       20490 :                     if (estate->retistuple && !estate->retisnull)
    3188           4 :                         ereport(ERROR,
    3189             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3190             :                                  errmsg("cannot return non-composite value from function returning composite type")));
    3191             :                 }
    3192       20486 :                 break;
    3193             : 
    3194             :             case PLPGSQL_DTYPE_REC:
    3195             :                 {
    3196        8178 :                     PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar;
    3197             : 
    3198             :                     /* If record is empty, we return NULL not a row of nulls */
    3199        8178 :                     if (rec->erh && !ExpandedRecordIsEmpty(rec->erh))
    3200             :                     {
    3201        8126 :                         estate->retval = ExpandedRecordGetDatum(rec->erh);
    3202        8126 :                         estate->retisnull = false;
    3203        8126 :                         estate->rettype = rec->rectypeid;
    3204             :                     }
    3205             :                 }
    3206        8178 :                 break;
    3207             : 
    3208             :             case PLPGSQL_DTYPE_ROW:
    3209             :                 {
    3210          80 :                     PLpgSQL_row *row = (PLpgSQL_row *) retvar;
    3211             :                     int32       rettypmod;
    3212             : 
    3213             :                     /* We get here if there are multiple OUT parameters */
    3214          80 :                     exec_eval_datum(estate,
    3215             :                                     (PLpgSQL_datum *) row,
    3216             :                                     &estate->rettype,
    3217             :                                     &rettypmod,
    3218             :                                     &estate->retval,
    3219             :                                     &estate->retisnull);
    3220             :                 }
    3221          80 :                 break;
    3222             : 
    3223             :             default:
    3224           0 :                 elog(ERROR, "unrecognized dtype: %d", retvar->dtype);
    3225             :         }
    3226             : 
    3227       28744 :         return PLPGSQL_RC_RETURN;
    3228             :     }
    3229             : 
    3230       35230 :     if (stmt->expr != NULL)
    3231             :     {
    3232             :         int32       rettypmod;
    3233             : 
    3234       33222 :         estate->retval = exec_eval_expr(estate, stmt->expr,
    3235             :                                         &(estate->retisnull),
    3236             :                                         &(estate->rettype),
    3237             :                                         &rettypmod);
    3238             : 
    3239             :         /*
    3240             :          * As in the DTYPE_VAR case above, throw a custom error if a non-null,
    3241             :          * non-composite value is returned in a function returning tuple.
    3242             :          */
    3243       33264 :         if (estate->retistuple && !estate->retisnull &&
    3244          78 :             !type_is_rowtype(estate->rettype))
    3245           4 :             ereport(ERROR,
    3246             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    3247             :                      errmsg("cannot return non-composite value from function returning composite type")));
    3248             : 
    3249       33182 :         return PLPGSQL_RC_RETURN;
    3250             :     }
    3251             : 
    3252             :     /*
    3253             :      * Special hack for function returning VOID: instead of NULL, return a
    3254             :      * non-null VOID value.  This is of dubious importance but is kept for
    3255             :      * backwards compatibility.  We don't do it for procedures, though.
    3256             :      */
    3257        4016 :     if (estate->fn_rettype == VOIDOID &&
    3258        2008 :         estate->func->fn_prokind != PROKIND_PROCEDURE)
    3259             :     {
    3260        1974 :         estate->retval = (Datum) 0;
    3261        1974 :         estate->retisnull = false;
    3262        1974 :         estate->rettype = VOIDOID;
    3263             :     }
    3264             : 
    3265        2008 :     return PLPGSQL_RC_RETURN;
    3266             : }
    3267             : 
    3268             : /* ----------
    3269             :  * exec_stmt_return_next        Evaluate an expression and add it to the
    3270             :  *                              list of tuples returned by the current
    3271             :  *                              SRF.
    3272             :  * ----------
    3273             :  */
    3274             : static int
    3275        1594 : exec_stmt_return_next(PLpgSQL_execstate *estate,
    3276             :                       PLpgSQL_stmt_return_next *stmt)
    3277             : {
    3278             :     TupleDesc   tupdesc;
    3279             :     int         natts;
    3280             :     HeapTuple   tuple;
    3281             :     MemoryContext oldcontext;
    3282             : 
    3283        1594 :     if (!estate->retisset)
    3284           0 :         ereport(ERROR,
    3285             :                 (errcode(ERRCODE_SYNTAX_ERROR),
    3286             :                  errmsg("cannot use RETURN NEXT in a non-SETOF function")));
    3287             : 
    3288        1594 :     if (estate->tuple_store == NULL)
    3289         354 :         exec_init_tuple_store(estate);
    3290             : 
    3291             :     /* tuple_store_desc will be filled by exec_init_tuple_store */
    3292        1594 :     tupdesc = estate->tuple_store_desc;
    3293        1594 :     natts = tupdesc->natts;
    3294             : 
    3295             :     /*
    3296             :      * Special case path when the RETURN NEXT expression is a simple variable
    3297             :      * reference; in particular, this path is always taken in functions with
    3298             :      * one or more OUT parameters.
    3299             :      *
    3300             :      * Unlike exec_stmt_return, there's no special win here for R/W expanded
    3301             :      * values, since they'll have to get flattened to go into the tuplestore.
    3302             :      * Indeed, we'd better make them R/O to avoid any risk of the casting step
    3303             :      * changing them in-place.
    3304             :      */
    3305        1594 :     if (stmt->retvarno >= 0)
    3306             :     {
    3307        1228 :         PLpgSQL_datum *retvar = estate->datums[stmt->retvarno];
    3308             : 
    3309        1228 :         switch (retvar->dtype)
    3310             :         {
    3311             :             case PLPGSQL_DTYPE_PROMISE:
    3312             :                 /* fulfill promise if needed, then handle like regular var */
    3313           0 :                 plpgsql_fulfill_promise(estate, (PLpgSQL_var *) retvar);
    3314             : 
    3315             :                 /* FALL THRU */
    3316             : 
    3317             :             case PLPGSQL_DTYPE_VAR:
    3318             :                 {
    3319        1000 :                     PLpgSQL_var *var = (PLpgSQL_var *) retvar;
    3320        1000 :                     Datum       retval = var->value;
    3321        1000 :                     bool        isNull = var->isnull;
    3322        1000 :                     Form_pg_attribute attr = TupleDescAttr(tupdesc, 0);
    3323             : 
    3324        1000 :                     if (natts != 1)
    3325           0 :                         ereport(ERROR,
    3326             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3327             :                                  errmsg("wrong result type supplied in RETURN NEXT")));
    3328             : 
    3329             :                     /* let's be very paranoid about the cast step */
    3330        1000 :                     retval = MakeExpandedObjectReadOnly(retval,
    3331             :                                                         isNull,
    3332             :                                                         var->datatype->typlen);
    3333             : 
    3334             :                     /* coerce type if needed */
    3335        3000 :                     retval = exec_cast_value(estate,
    3336             :                                              retval,
    3337             :                                              &isNull,
    3338        1000 :                                              var->datatype->typoid,
    3339        1000 :                                              var->datatype->atttypmod,
    3340             :                                              attr->atttypid,
    3341             :                                              attr->atttypmod);
    3342             : 
    3343        1000 :                     tuplestore_putvalues(estate->tuple_store, tupdesc,
    3344             :                                          &retval, &isNull);
    3345             :                 }
    3346        1000 :                 break;
    3347             : 
    3348             :             case PLPGSQL_DTYPE_REC:
    3349             :                 {
    3350         132 :                     PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar;
    3351             :                     TupleDesc   rec_tupdesc;
    3352             :                     TupleConversionMap *tupmap;
    3353             : 
    3354             :                     /* If rec is null, try to convert it to a row of nulls */
    3355         132 :                     if (rec->erh == NULL)
    3356           4 :                         instantiate_empty_record_variable(estate, rec);
    3357         130 :                     if (ExpandedRecordIsEmpty(rec->erh))
    3358           2 :                         deconstruct_expanded_record(rec->erh);
    3359             : 
    3360             :                     /* Use eval_mcontext for tuple conversion work */
    3361         130 :                     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    3362         130 :                     rec_tupdesc = expanded_record_get_tupdesc(rec->erh);
    3363         130 :                     tupmap = convert_tuples_by_position(rec_tupdesc,
    3364             :                                                         tupdesc,
    3365             :                                                         gettext_noop("wrong record type supplied in RETURN NEXT"));
    3366         130 :                     tuple = expanded_record_get_tuple(rec->erh);
    3367         130 :                     if (tupmap)
    3368          22 :                         tuple = execute_attr_map_tuple(tuple, tupmap);
    3369         130 :                     tuplestore_puttuple(estate->tuple_store, tuple);
    3370         130 :                     MemoryContextSwitchTo(oldcontext);
    3371             :                 }
    3372         130 :                 break;
    3373             : 
    3374             :             case PLPGSQL_DTYPE_ROW:
    3375             :                 {
    3376          96 :                     PLpgSQL_row *row = (PLpgSQL_row *) retvar;
    3377             : 
    3378             :                     /* We get here if there are multiple OUT parameters */
    3379             : 
    3380             :                     /* Use eval_mcontext for tuple conversion work */
    3381          96 :                     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    3382          96 :                     tuple = make_tuple_from_row(estate, row, tupdesc);
    3383          96 :                     if (tuple == NULL)  /* should not happen */
    3384           0 :                         ereport(ERROR,
    3385             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3386             :                                  errmsg("wrong record type supplied in RETURN NEXT")));
    3387          96 :                     tuplestore_puttuple(estate->tuple_store, tuple);
    3388          96 :                     MemoryContextSwitchTo(oldcontext);
    3389             :                 }
    3390          96 :                 break;
    3391             : 
    3392             :             default:
    3393           0 :                 elog(ERROR, "unrecognized dtype: %d", retvar->dtype);
    3394             :                 break;
    3395             :         }
    3396             :     }
    3397         366 :     else if (stmt->expr)
    3398             :     {
    3399             :         Datum       retval;
    3400             :         bool        isNull;
    3401             :         Oid         rettype;
    3402             :         int32       rettypmod;
    3403             : 
    3404         366 :         retval = exec_eval_expr(estate,
    3405             :                                 stmt->expr,
    3406             :                                 &isNull,
    3407             :                                 &rettype,
    3408             :                                 &rettypmod);
    3409             : 
    3410         366 :         if (estate->retistuple)
    3411             :         {
    3412             :             /* Expression should be of RECORD or composite type */
    3413         326 :             if (!isNull)
    3414             :             {
    3415             :                 HeapTupleData tmptup;
    3416             :                 TupleDesc   retvaldesc;
    3417             :                 TupleConversionMap *tupmap;
    3418             : 
    3419         322 :                 if (!type_is_rowtype(rettype))
    3420           0 :                     ereport(ERROR,
    3421             :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
    3422             :                              errmsg("cannot return non-composite value from function returning composite type")));
    3423             : 
    3424             :                 /* Use eval_mcontext for tuple conversion work */
    3425         322 :                 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    3426         322 :                 retvaldesc = deconstruct_composite_datum(retval, &tmptup);
    3427         322 :                 tuple = &tmptup;
    3428         322 :                 tupmap = convert_tuples_by_position(retvaldesc, tupdesc,
    3429             :                                                     gettext_noop("returned record type does not match expected record type"));
    3430         320 :                 if (tupmap)
    3431           2 :                     tuple = execute_attr_map_tuple(tuple, tupmap);
    3432         320 :                 tuplestore_puttuple(estate->tuple_store, tuple);
    3433         320 :                 ReleaseTupleDesc(retvaldesc);
    3434         320 :                 MemoryContextSwitchTo(oldcontext);
    3435             :             }
    3436             :             else
    3437             :             {
    3438             :                 /* Composite NULL --- store a row of nulls */
    3439             :                 Datum      *nulldatums;
    3440             :                 bool       *nullflags;
    3441             : 
    3442           4 :                 nulldatums = (Datum *)
    3443           4 :                     eval_mcontext_alloc0(estate, natts * sizeof(Datum));
    3444           4 :                 nullflags = (bool *)
    3445           4 :                     eval_mcontext_alloc(estate, natts * sizeof(bool));
    3446           4 :                 memset(nullflags, true, natts * sizeof(bool));
    3447           4 :                 tuplestore_putvalues(estate->tuple_store, tupdesc,
    3448             :                                      nulldatums, nullflags);
    3449             :             }
    3450             :         }
    3451             :         else
    3452             :         {
    3453          40 :             Form_pg_attribute attr = TupleDescAttr(tupdesc, 0);
    3454             : 
    3455             :             /* Simple scalar result */
    3456          40 :             if (natts != 1)
    3457           0 :                 ereport(ERROR,
    3458             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    3459             :                          errmsg("wrong result type supplied in RETURN NEXT")));
    3460             : 
    3461             :             /* coerce type if needed */
    3462          40 :             retval = exec_cast_value(estate,
    3463             :                                      retval,
    3464             :                                      &isNull,
    3465             :                                      rettype,
    3466             :                                      rettypmod,
    3467             :                                      attr->atttypid,
    3468             :                                      attr->atttypmod);
    3469             : 
    3470          40 :             tuplestore_putvalues(estate->tuple_store, tupdesc,
    3471             :                                  &retval, &isNull);
    3472             :         }
    3473             :     }
    3474             :     else
    3475             :     {
    3476           0 :         ereport(ERROR,
    3477             :                 (errcode(ERRCODE_SYNTAX_ERROR),
    3478             :                  errmsg("RETURN NEXT must have a parameter")));
    3479             :     }
    3480             : 
    3481        1590 :     exec_eval_cleanup(estate);
    3482             : 
    3483        1590 :     return PLPGSQL_RC_OK;
    3484             : }
    3485             : 
    3486             : /* ----------
    3487             :  * exec_stmt_return_query       Evaluate a query and add it to the
    3488             :  *                              list of tuples returned by the current
    3489             :  *                              SRF.
    3490             :  * ----------
    3491             :  */
    3492             : static int
    3493         362 : exec_stmt_return_query(PLpgSQL_execstate *estate,
    3494             :                        PLpgSQL_stmt_return_query *stmt)
    3495             : {
    3496             :     Portal      portal;
    3497         362 :     uint64      processed = 0;
    3498             :     TupleConversionMap *tupmap;
    3499             :     MemoryContext oldcontext;
    3500             : 
    3501         362 :     if (!estate->retisset)
    3502           0 :         ereport(ERROR,
    3503             :                 (errcode(ERRCODE_SYNTAX_ERROR),
    3504             :                  errmsg("cannot use RETURN QUERY in a non-SETOF function")));
    3505             : 
    3506         362 :     if (estate->tuple_store == NULL)
    3507         326 :         exec_init_tuple_store(estate);
    3508             : 
    3509         362 :     if (stmt->query != NULL)
    3510             :     {
    3511             :         /* static query */
    3512         330 :         exec_run_select(estate, stmt->query, 0, &portal);
    3513             :     }
    3514             :     else
    3515             :     {
    3516             :         /* RETURN QUERY EXECUTE */
    3517             :         Assert(stmt->dynquery != NULL);
    3518          32 :         portal = exec_dynquery_with_params(estate, stmt->dynquery,
    3519             :                                            stmt->params, NULL,
    3520             :                                            0);
    3521             :     }
    3522             : 
    3523             :     /* Use eval_mcontext for tuple conversion work */
    3524         362 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    3525             : 
    3526         362 :     tupmap = convert_tuples_by_position(portal->tupDesc,
    3527             :                                         estate->tuple_store_desc,
    3528             :                                         gettext_noop("structure of query does not match function result type"));
    3529             : 
    3530             :     while (true)
    3531         346 :     {
    3532             :         uint64      i;
    3533             : 
    3534         708 :         SPI_cursor_fetch(portal, true, 50);
    3535             : 
    3536             :         /* SPI will have changed CurrentMemoryContext */
    3537         708 :         MemoryContextSwitchTo(get_eval_mcontext(estate));
    3538             : 
    3539         708 :         if (SPI_processed == 0)
    3540         362 :             break;
    3541             : 
    3542         926 :         for (i = 0; i < SPI_processed; i++)
    3543             :         {
    3544         580 :             HeapTuple   tuple = SPI_tuptable->vals[i];
    3545             : 
    3546         580 :             if (tupmap)
    3547          48 :                 tuple = execute_attr_map_tuple(tuple, tupmap);
    3548         580 :             tuplestore_puttuple(estate->tuple_store, tuple);
    3549         580 :             if (tupmap)
    3550          48 :                 heap_freetuple(tuple);
    3551         580 :             processed++;
    3552             :         }
    3553             : 
    3554         346 :         SPI_freetuptable(SPI_tuptable);
    3555             :     }
    3556             : 
    3557         362 :     SPI_freetuptable(SPI_tuptable);
    3558         362 :     SPI_cursor_close(portal);
    3559             : 
    3560         362 :     MemoryContextSwitchTo(oldcontext);
    3561         362 :     exec_eval_cleanup(estate);
    3562             : 
    3563         362 :     estate->eval_processed = processed;
    3564         362 :     exec_set_found(estate, processed != 0);
    3565             : 
    3566         362 :     return PLPGSQL_RC_OK;
    3567             : }
    3568             : 
    3569             : static void
    3570         680 : exec_init_tuple_store(PLpgSQL_execstate *estate)
    3571             : {
    3572         680 :     ReturnSetInfo *rsi = estate->rsi;
    3573             :     MemoryContext oldcxt;
    3574             :     ResourceOwner oldowner;
    3575             : 
    3576             :     /*
    3577             :      * Check caller can handle a set result in the way we want
    3578             :      */
    3579        1360 :     if (!rsi || !IsA(rsi, ReturnSetInfo) ||
    3580        1360 :         (rsi->allowedModes & SFRM_Materialize) == 0 ||
    3581         680 :         rsi->expectedDesc == NULL)
    3582           0 :         ereport(ERROR,
    3583             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3584             :                  errmsg("set-valued function called in context that cannot accept a set")));
    3585             : 
    3586             :     /*
    3587             :      * Switch to the right memory context and resource owner for storing the
    3588             :      * tuplestore for return set. If we're within a subtransaction opened for
    3589             :      * an exception-block, for example, we must still create the tuplestore in
    3590             :      * the resource owner that was active when this function was entered, and
    3591             :      * not in the subtransaction resource owner.
    3592             :      */
    3593         680 :     oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
    3594         680 :     oldowner = CurrentResourceOwner;
    3595         680 :     CurrentResourceOwner = estate->tuple_store_owner;
    3596             : 
    3597         680 :     estate->tuple_store =
    3598         680 :         tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
    3599             :                               false, work_mem);
    3600             : 
    3601         680 :     CurrentResourceOwner = oldowner;
    3602         680 :     MemoryContextSwitchTo(oldcxt);
    3603             : 
    3604         680 :     estate->tuple_store_desc = rsi->expectedDesc;
    3605         680 : }
    3606             : 
    3607             : #define SET_RAISE_OPTION_TEXT(opt, name) \
    3608             : do { \
    3609             :     if (opt) \
    3610             :         ereport(ERROR, \
    3611             :                 (errcode(ERRCODE_SYNTAX_ERROR), \
    3612             :                  errmsg("RAISE option already specified: %s", \
    3613             :                         name))); \
    3614             :     opt = MemoryContextStrdup(stmt_mcontext, extval); \
    3615             : } while (0)
    3616             : 
    3617             : /* ----------
    3618             :  * exec_stmt_raise          Build a message and throw it with elog()
    3619             :  * ----------
    3620             :  */
    3621             : static int
    3622        6792 : exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
    3623             : {
    3624        6792 :     int         err_code = 0;
    3625        6792 :     char       *condname = NULL;
    3626        6792 :     char       *err_message = NULL;
    3627        6792 :     char       *err_detail = NULL;
    3628        6792 :     char       *err_hint = NULL;
    3629        6792 :     char       *err_column = NULL;
    3630        6792 :     char       *err_constraint = NULL;
    3631        6792 :     char       *err_datatype = NULL;
    3632        6792 :     char       *err_table = NULL;
    3633        6792 :     char       *err_schema = NULL;
    3634             :     MemoryContext stmt_mcontext;
    3635             :     ListCell   *lc;
    3636             : 
    3637             :     /* RAISE with no parameters: re-throw current exception */
    3638        6828 :     if (stmt->condname == NULL && stmt->message == NULL &&
    3639          36 :         stmt->options == NIL)
    3640             :     {
    3641          24 :         if (estate->cur_error != NULL)
    3642          20 :             ReThrowError(estate->cur_error);
    3643             :         /* oops, we're not inside a handler */
    3644           4 :         ereport(ERROR,
    3645             :                 (errcode(ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER),
    3646             :                  errmsg("RAISE without parameters cannot be used outside an exception handler")));
    3647             :     }
    3648             : 
    3649             :     /* We'll need to accumulate the various strings in stmt_mcontext */
    3650        6768 :     stmt_mcontext = get_stmt_mcontext(estate);
    3651             : 
    3652        6768 :     if (stmt->condname)
    3653             :     {
    3654          40 :         err_code = plpgsql_recognize_err_condition(stmt->condname, true);
    3655          40 :         condname = MemoryContextStrdup(stmt_mcontext, stmt->condname);
    3656             :     }
    3657             : 
    3658        6768 :     if (stmt->message)
    3659             :     {
    3660             :         StringInfoData ds;
    3661             :         ListCell   *current_param;
    3662             :         char       *cp;
    3663             :         MemoryContext oldcontext;
    3664             : 
    3665             :         /* build string in stmt_mcontext */
    3666        6716 :         oldcontext = MemoryContextSwitchTo(stmt_mcontext);
    3667        6716 :         initStringInfo(&ds);
    3668        6716 :         MemoryContextSwitchTo(oldcontext);
    3669             : 
    3670        6716 :         current_param = list_head(stmt->params);
    3671             : 
    3672      126550 :         for (cp = stmt->message; *cp; cp++)
    3673             :         {
    3674             :             /*
    3675             :              * Occurrences of a single % are replaced by the next parameter's
    3676             :              * external representation. Double %'s are converted to one %.
    3677             :              */
    3678      119854 :             if (cp[0] == '%')
    3679             :             {
    3680             :                 Oid         paramtypeid;
    3681             :                 int32       paramtypmod;
    3682             :                 Datum       paramvalue;
    3683             :                 bool        paramisnull;
    3684             :                 char       *extval;
    3685             : 
    3686       14804 :                 if (cp[1] == '%')
    3687             :                 {
    3688           4 :                     appendStringInfoChar(&ds, '%');
    3689           4 :                     cp++;
    3690           4 :                     continue;
    3691             :                 }
    3692             : 
    3693             :                 /* should have been checked at compile time */
    3694       14800 :                 if (current_param == NULL)
    3695           0 :                     elog(ERROR, "unexpected RAISE parameter list length");
    3696             : 
    3697       14800 :                 paramvalue = exec_eval_expr(estate,
    3698       14800 :                                             (PLpgSQL_expr *) lfirst(current_param),
    3699             :                                             &paramisnull,
    3700             :                                             &paramtypeid,
    3701             :                                             &paramtypmod);
    3702             : 
    3703       14780 :                 if (paramisnull)
    3704          94 :                     extval = "<NULL>";
    3705             :                 else
    3706       14686 :                     extval = convert_value_to_string(estate,
    3707             :                                                      paramvalue,
    3708             :                                                      paramtypeid);
    3709       14780 :                 appendStringInfoString(&ds, extval);
    3710       14780 :                 current_param = lnext(stmt->params, current_param);
    3711       14780 :                 exec_eval_cleanup(estate);
    3712             :             }
    3713             :             else
    3714      105050 :                 appendStringInfoChar(&ds, cp[0]);
    3715             :         }
    3716             : 
    3717             :         /* should have been checked at compile time */
    3718        6696 :         if (current_param != NULL)
    3719           0 :             elog(ERROR, "unexpected RAISE parameter list length");
    3720             : 
    3721        6696 :         err_message = ds.data;
    3722             :     }
    3723             : 
    3724        6868 :     foreach(lc, stmt->options)
    3725             :     {
    3726         128 :         PLpgSQL_raise_option *opt = (PLpgSQL_raise_option *) lfirst(lc);
    3727             :         Datum       optionvalue;
    3728             :         bool        optionisnull;
    3729             :         Oid         optiontypeid;
    3730             :         int32       optiontypmod;
    3731             :         char       *extval;
    3732             : 
    3733         128 :         optionvalue = exec_eval_expr(estate, opt->expr,
    3734             :                                      &optionisnull,
    3735             :                                      &optiontypeid,
    3736             :                                      &optiontypmod);
    3737         128 :         if (optionisnull)
    3738           0 :             ereport(ERROR,
    3739             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    3740             :                      errmsg("RAISE statement option cannot be null")));
    3741             : 
    3742         128 :         extval = convert_value_to_string(estate, optionvalue, optiontypeid);
    3743             : 
    3744         128 :         switch (opt->opt_type)
    3745             :         {
    3746             :             case PLPGSQL_RAISEOPTION_ERRCODE:
    3747          28 :                 if (err_code)
    3748           4 :                     ereport(ERROR,
    3749             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    3750             :                              errmsg("RAISE option already specified: %s",
    3751             :                                     "ERRCODE")));
    3752          24 :                 err_code = plpgsql_recognize_err_condition(extval, true);
    3753          24 :                 condname = MemoryContextStrdup(stmt_mcontext, extval);
    3754          24 :                 break;
    3755             :             case PLPGSQL_RAISEOPTION_MESSAGE:
    3756          28 :                 SET_RAISE_OPTION_TEXT(err_message, "MESSAGE");
    3757          24 :                 break;
    3758             :             case PLPGSQL_RAISEOPTION_DETAIL:
    3759          32 :                 SET_RAISE_OPTION_TEXT(err_detail, "DETAIL");
    3760          32 :                 break;
    3761             :             case PLPGSQL_RAISEOPTION_HINT:
    3762          10 :                 SET_RAISE_OPTION_TEXT(err_hint, "HINT");
    3763          10 :                 break;
    3764             :             case PLPGSQL_RAISEOPTION_COLUMN:
    3765           6 :                 SET_RAISE_OPTION_TEXT(err_column, "COLUMN");
    3766           6 :                 break;
    3767             :             case PLPGSQL_RAISEOPTION_CONSTRAINT:
    3768           6 :                 SET_RAISE_OPTION_TEXT(err_constraint, "CONSTRAINT");
    3769           6 :                 break;
    3770             :             case PLPGSQL_RAISEOPTION_DATATYPE:
    3771           6 :                 SET_RAISE_OPTION_TEXT(err_datatype, "DATATYPE");
    3772           6 :                 break;
    3773             :             case PLPGSQL_RAISEOPTION_TABLE:
    3774           6 :                 SET_RAISE_OPTION_TEXT(err_table, "TABLE");
    3775           6 :                 break;
    3776             :             case PLPGSQL_RAISEOPTION_SCHEMA:
    3777           6 :                 SET_RAISE_OPTION_TEXT(err_schema, "SCHEMA");
    3778           6 :                 break;
    3779             :             default:
    3780           0 :                 elog(ERROR, "unrecognized raise option: %d", opt->opt_type);
    3781             :         }
    3782             : 
    3783         120 :         exec_eval_cleanup(estate);
    3784             :     }
    3785             : 
    3786             :     /* Default code if nothing specified */
    3787        6740 :     if (err_code == 0 && stmt->elog_level >= ERROR)
    3788         102 :         err_code = ERRCODE_RAISE_EXCEPTION;
    3789             : 
    3790             :     /* Default error message if nothing specified */
    3791        6740 :     if (err_message == NULL)
    3792             :     {
    3793          28 :         if (condname)
    3794             :         {
    3795          24 :             err_message = condname;
    3796          24 :             condname = NULL;
    3797             :         }
    3798             :         else
    3799           4 :             err_message = MemoryContextStrdup(stmt_mcontext,
    3800           4 :                                               unpack_sql_state(err_code));
    3801             :     }
    3802             : 
    3803             :     /*
    3804             :      * Throw the error (may or may not come back)
    3805             :      */
    3806        6740 :     ereport(stmt->elog_level,
    3807             :             (err_code ? errcode(err_code) : 0,
    3808             :              errmsg_internal("%s", err_message),
    3809             :              (err_detail != NULL) ? errdetail_internal("%s", err_detail) : 0,
    3810             :              (err_hint != NULL) ? errhint("%s", err_hint) : 0,
    3811             :              (err_column != NULL) ?
    3812             :              err_generic_string(PG_DIAG_COLUMN_NAME, err_column) : 0,
    3813             :              (err_constraint != NULL) ?
    3814             :              err_generic_string(PG_DIAG_CONSTRAINT_NAME, err_constraint) : 0,
    3815             :              (err_datatype != NULL) ?
    3816             :              err_generic_string(PG_DIAG_DATATYPE_NAME, err_datatype) : 0,
    3817             :              (err_table != NULL) ?
    3818             :              err_generic_string(PG_DIAG_TABLE_NAME, err_table) : 0,
    3819             :              (err_schema != NULL) ?
    3820             :              err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0));
    3821             : 
    3822             :     /* Clean up transient strings */
    3823        6582 :     MemoryContextReset(stmt_mcontext);
    3824             : 
    3825        6582 :     return PLPGSQL_RC_OK;
    3826             : }
    3827             : 
    3828             : /* ----------
    3829             :  * exec_stmt_assert         Assert statement
    3830             :  * ----------
    3831             :  */
    3832             : static int
    3833          34 : exec_stmt_assert(PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
    3834             : {
    3835             :     bool        value;
    3836             :     bool        isnull;
    3837             : 
    3838             :     /* do nothing when asserts are not enabled */
    3839          34 :     if (!plpgsql_check_asserts)
    3840           4 :         return PLPGSQL_RC_OK;
    3841             : 
    3842          30 :     value = exec_eval_boolean(estate, stmt->cond, &isnull);
    3843          30 :     exec_eval_cleanup(estate);
    3844             : 
    3845          30 :     if (isnull || !value)
    3846             :     {
    3847          16 :         char       *message = NULL;
    3848             : 
    3849          16 :         if (stmt->message != NULL)
    3850             :         {
    3851             :             Datum       val;
    3852             :             Oid         typeid;
    3853             :             int32       typmod;
    3854             : 
    3855           8 :             val = exec_eval_expr(estate, stmt->message,
    3856             :                                  &isnull, &typeid, &typmod);
    3857           8 :             if (!isnull)
    3858           8 :                 message = convert_value_to_string(estate, val, typeid);
    3859             :             /* we mustn't do exec_eval_cleanup here */
    3860             :         }
    3861             : 
    3862          16 :         ereport(ERROR,
    3863             :                 (errcode(ERRCODE_ASSERT_FAILURE),
    3864             :                  message ? errmsg_internal("%s", message) :
    3865             :                  errmsg("assertion failed")));
    3866             :     }
    3867             : 
    3868          14 :     return PLPGSQL_RC_OK;
    3869             : }
    3870             : 
    3871             : /* ----------
    3872             :  * Initialize a mostly empty execution state
    3873             :  * ----------
    3874             :  */
    3875             : static void
    3876       65268 : plpgsql_estate_setup(PLpgSQL_execstate *estate,
    3877             :                      PLpgSQL_function *func,
    3878             :                      ReturnSetInfo *rsi,
    3879             :                      EState *simple_eval_estate)
    3880             : {
    3881             :     HASHCTL     ctl;
    3882             : 
    3883             :     /* this link will be restored at exit from plpgsql_call_handler */
    3884       65268 :     func->cur_estate = estate;
    3885             : 
    3886       65268 :     estate->func = func;
    3887       65268 :     estate->trigdata = NULL;
    3888       65268 :     estate->evtrigdata = NULL;
    3889             : 
    3890       65268 :     estate->retval = (Datum) 0;
    3891       65268 :     estate->retisnull = true;
    3892       65268 :     estate->rettype = InvalidOid;
    3893             : 
    3894       65268 :     estate->fn_rettype = func->fn_rettype;
    3895       65268 :     estate->retistuple = func->fn_retistuple;
    3896       65268 :     estate->retisset = func->fn_retset;
    3897             : 
    3898       65268 :     estate->readonly_func = func->fn_readonly;
    3899       65268 :     estate->atomic = true;
    3900             : 
    3901       65268 :     estate->exitlabel = NULL;
    3902       65268 :     estate->cur_error = NULL;
    3903             : 
    3904       65268 :     estate->tuple_store = NULL;
    3905       65268 :     estate->tuple_store_desc = NULL;
    3906       65268 :     if (rsi)
    3907             :     {
    3908         896 :         estate->tuple_store_cxt = rsi->econtext->ecxt_per_query_memory;
    3909         896 :         estate->tuple_store_owner = CurrentResourceOwner;
    3910             :     }
    3911             :     else
    3912             :     {
    3913       64372 :         estate->tuple_store_cxt = NULL;
    3914       64372 :         estate->tuple_store_owner = NULL;
    3915             :     }
    3916       65268 :     estate->rsi = rsi;
    3917             : 
    3918       65268 :     estate->found_varno = func->found_varno;
    3919       65268 :     estate->ndatums = func->ndatums;
    3920       65268 :     estate->datums = NULL;
    3921             :     /* the datums array will be filled by copy_plpgsql_datums() */
    3922       65268 :     estate->datum_context = CurrentMemoryContext;
    3923             : 
    3924             :     /* initialize our ParamListInfo with appropriate hook functions */
    3925       65268 :     estate->paramLI = makeParamList(0);
    3926       65268 :     estate->paramLI->paramFetch = plpgsql_param_fetch;
    3927       65268 :     estate->paramLI->paramFetchArg = (void *) estate;
    3928       65268 :     estate->paramLI->paramCompile = plpgsql_param_compile;
    3929       65268 :     estate->paramLI->paramCompileArg = NULL;  /* not needed */
    3930       65268 :     estate->paramLI->parserSetup = (ParserSetupHook) plpgsql_parser_setup;
    3931       65268 :     estate->paramLI->parserSetupArg = NULL; /* filled during use */
    3932       65268 :     estate->paramLI->numParams = estate->ndatums;
    3933             : 
    3934             :     /* set up for use of appropriate simple-expression EState and cast hash */
    3935       65268 :     if (simple_eval_estate)
    3936             :     {
    3937         406 :         estate->simple_eval_estate = simple_eval_estate;
    3938             :         /* Private cast hash just lives in function's main context */
    3939         406 :         memset(&ctl, 0, sizeof(ctl));
    3940         406 :         ctl.keysize = sizeof(plpgsql_CastHashKey);
    3941         406 :         ctl.entrysize = sizeof(plpgsql_CastHashEntry);
    3942         406 :         ctl.hcxt = CurrentMemoryContext;
    3943         406 :         estate->cast_hash = hash_create("PLpgSQL private cast cache",
    3944             :                                         16, /* start small and extend */
    3945             :                                         &ctl,
    3946             :                                         HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
    3947         406 :         estate->cast_hash_context = CurrentMemoryContext;
    3948             :     }
    3949             :     else
    3950             :     {
    3951       64862 :         estate->simple_eval_estate = shared_simple_eval_estate;
    3952             :         /* Create the session-wide cast-info hash table if we didn't already */
    3953       64862 :         if (shared_cast_hash == NULL)
    3954             :         {
    3955         290 :             shared_cast_context = AllocSetContextCreate(TopMemoryContext,
    3956             :                                                         "PLpgSQL cast info",
    3957             :                                                         ALLOCSET_DEFAULT_SIZES);
    3958         290 :             memset(&ctl, 0, sizeof(ctl));
    3959         290 :             ctl.keysize = sizeof(plpgsql_CastHashKey);
    3960         290 :             ctl.entrysize = sizeof(plpgsql_CastHashEntry);
    3961         290 :             ctl.hcxt = shared_cast_context;
    3962         290 :             shared_cast_hash = hash_create("PLpgSQL cast cache",
    3963             :                                            16,  /* start small and extend */
    3964             :                                            &ctl,
    3965             :                                            HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
    3966             :         }
    3967       64862 :         estate->cast_hash = shared_cast_hash;
    3968       64862 :         estate->cast_hash_context = shared_cast_context;
    3969             :     }
    3970             : 
    3971             :     /*
    3972             :      * We start with no stmt_mcontext; one will be created only if needed.
    3973             :      * That context will be a direct child of the function's main execution
    3974             :      * context.  Additional stmt_mcontexts might be created as children of it.
    3975             :      */
    3976       65268 :     estate->stmt_mcontext = NULL;
    3977       65268 :     estate->stmt_mcontext_parent = CurrentMemoryContext;
    3978             : 
    3979       65268 :     estate->eval_tuptable = NULL;
    3980       65268 :     estate->eval_processed = 0;
    3981       65268 :     estate->eval_econtext = NULL;
    3982             : 
    3983       65268 :     estate->err_stmt = NULL;
    3984       65268 :     estate->err_text = NULL;
    3985             : 
    3986       65268 :     estate->plugin_info = NULL;
    3987             : 
    3988             :     /*
    3989             :      * Create an EState and ExprContext for evaluation of simple expressions.
    3990             :      */
    3991       65268 :     plpgsql_create_econtext(estate);
    3992             : 
    3993             :     /*
    3994             :      * Let the plugin see this function before we initialize any local
    3995             :      * PL/pgSQL variables - note that we also give the plugin a few function
    3996             :      * pointers so it can call back into PL/pgSQL for doing things like
    3997             :      * variable assignments and stack traces
    3998             :      */
    3999       65268 :     if (*plpgsql_plugin_ptr)
    4000             :     {
    4001           0 :         (*plpgsql_plugin_ptr)->error_callback = plpgsql_exec_error_callback;
    4002           0 :         (*plpgsql_plugin_ptr)->assign_expr = exec_assign_expr;
    4003             : 
    4004           0 :         if ((*plpgsql_plugin_ptr)->func_setup)
    4005           0 :             ((*plpgsql_plugin_ptr)->func_setup) (estate, func);
    4006             :     }
    4007       65268 : }
    4008             : 
    4009             : /* ----------
    4010             :  * Release temporary memory used by expression/subselect evaluation
    4011             :  *
    4012             :  * NB: the result of the evaluation is no longer valid after this is done,
    4013             :  * unless it is a pass-by-value datatype.
    4014             :  *
    4015             :  * NB: if you change this code, see also the hacks in exec_assign_value's
    4016             :  * PLPGSQL_DTYPE_ARRAYELEM case for partial cleanup after subscript evals.
    4017             :  * ----------
    4018             :  */
    4019             : static void
    4020      205572 : exec_eval_cleanup(PLpgSQL_execstate *estate)
    4021             : {
    4022             :     /* Clear result of a full SPI_execute */
    4023      205572 :     if (estate->eval_tuptable != NULL)
    4024        5180 :         SPI_freetuptable(estate->eval_tuptable);
    4025      205572 :     estate->eval_tuptable = NULL;
    4026             : 
    4027             :     /*
    4028             :      * Clear result of exec_eval_simple_expr (but keep the econtext).  This
    4029             :      * also clears any short-lived allocations done via get_eval_mcontext.
    4030             :      */
    4031      205572 :     if (estate->eval_econtext != NULL)
    4032      141016 :         ResetExprContext(estate->eval_econtext);
    4033      205572 : }
    4034             : 
    4035             : 
    4036             : /* ----------
    4037             :  * Generate a prepared plan
    4038             :  * ----------
    4039             :  */
    4040             : static void
    4041       10428 : exec_prepare_plan(PLpgSQL_execstate *estate,
    4042             :                   PLpgSQL_expr *expr, int cursorOptions,
    4043             :                   bool keepplan)
    4044             : {
    4045             :     SPIPlanPtr  plan;
    4046             : 
    4047             :     /*
    4048             :      * The grammar can't conveniently set expr->func while building the parse
    4049             :      * tree, so make sure it's set before parser hooks need it.
    4050             :      */
    4051       10428 :     expr->func = estate->func;
    4052             : 
    4053             :     /*
    4054             :      * Generate and save the plan
    4055             :      */
    4056       10428 :     plan = SPI_prepare_params(expr->query,
    4057             :                               (ParserSetupHook) plpgsql_parser_setup,
    4058             :                               (void *) expr,
    4059             :                               cursorOptions);
    4060       10400 :     if (plan == NULL)
    4061           0 :         elog(ERROR, "SPI_prepare_params failed for \"%s\": %s",
    4062             :              expr->query, SPI_result_code_string(SPI_result));
    4063       10400 :     if (keepplan)
    4064       10342 :         SPI_keepplan(plan);
    4065       10400 :     expr->plan = plan;
    4066             : 
    4067             :     /* Check to see if it's a simple expression */
    4068       10400 :     exec_simple_check_plan(estate, expr);
    4069             : 
    4070             :     /*
    4071             :      * Mark expression as not using a read-write param.  exec_assign_value has
    4072             :      * to take steps to override this if appropriate; that seems cleaner than
    4073             :      * adding parameters to all other callers.
    4074             :      */
    4075       10378 :     expr->rwparam = -1;
    4076       10378 : }
    4077             : 
    4078             : 
    4079             : /* ----------
    4080             :  * exec_stmt_execsql            Execute an SQL statement (possibly with INTO).
    4081             :  *
    4082             :  * Note: some callers rely on this not touching stmt_mcontext.  If it ever
    4083             :  * needs to use that, fix those callers to push/pop stmt_mcontext.
    4084             :  * ----------
    4085             :  */
    4086             : static int
    4087        7006 : exec_stmt_execsql(PLpgSQL_execstate *estate,
    4088             :                   PLpgSQL_stmt_execsql *stmt)
    4089             : {
    4090             :     ParamListInfo paramLI;
    4091             :     long        tcount;
    4092             :     int         rc;
    4093        7006 :     PLpgSQL_expr *expr = stmt->sqlstmt;
    4094        7006 :     int         too_many_rows_level = 0;
    4095             : 
    4096        7006 :     if (plpgsql_extra_errors & PLPGSQL_XCHECK_TOOMANYROWS)
    4097           4 :         too_many_rows_level = ERROR;
    4098        7002 :     else if (plpgsql_extra_warnings & PLPGSQL_XCHECK_TOOMANYROWS)
    4099           4 :         too_many_rows_level = WARNING;
    4100             : 
    4101             :     /*
    4102             :      * On the first call for this statement generate the plan, and detect
    4103             :      * whether the statement is INSERT/UPDATE/DELETE
    4104             :      */
    4105        7006 :     if (expr->plan == NULL)
    4106             :     {
    4107             :         ListCell   *l;
    4108             : 
    4109         710 :         exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK, true);
    4110         704 :         stmt->mod_stmt = false;
    4111        1078 :         foreach(l, SPI_plan_get_plan_sources(expr->plan))
    4112             :         {
    4113         704 :             CachedPlanSource *plansource = (CachedPlanSource *) lfirst(l);
    4114             : 
    4115             :             /*
    4116             :              * We could look at the raw_parse_tree, but it seems simpler to
    4117             :              * check the command tag.  Note we should *not* look at the Query
    4118             :              * tree(s), since those are the result of rewriting and could have
    4119             :              * been transmogrified into something else entirely.
    4120             :              */
    4121        1408 :             if (plansource->commandTag &&
    4122        1216 :                 (strcmp(plansource->commandTag, "INSERT") == 0 ||
    4123         928 :                  strcmp(plansource->commandTag, "UPDATE") == 0 ||
    4124         416 :                  strcmp(plansource->commandTag, "DELETE") == 0))
    4125             :             {
    4126         330 :                 stmt->mod_stmt = true;
    4127         330 :                 break;
    4128             :             }
    4129             :         }
    4130             :     }
    4131             : 
    4132             :     /*
    4133             :      * Set up ParamListInfo to pass to executor
    4134             :      */
    4135        7000 :     paramLI = setup_param_list(estate, expr);
    4136             : 
    4137             :     /*
    4138             :      * If we have INTO, then we only need one row back ... but if we have INTO
    4139             :      * STRICT or extra check too_many_rows, ask for two rows, so that we can
    4140             :      * verify the statement returns only one.  INSERT/UPDATE/DELETE are always
    4141             :      * treated strictly. Without INTO, just run the statement to completion
    4142             :      * (tcount = 0).
    4143             :      *
    4144             :      * We could just ask for two rows always when using INTO, but there are
    4145             :      * some cases where demanding the extra row costs significant time, eg by
    4146             :      * forcing completion of a sequential scan.  So don't do it unless we need
    4147             :      * to enforce strictness.
    4148             :      */
    4149        7000 :     if (stmt->into)
    4150             :     {
    4151        2498 :         if (stmt->strict || stmt->mod_stmt || too_many_rows_level)
    4152         336 :             tcount = 2;
    4153             :         else
    4154        2162 :             tcount = 1;
    4155             :     }
    4156             :     else
    4157        4502 :         tcount = 0;
    4158             : 
    4159             :     /*
    4160             :      * Execute the plan
    4161             :      */
    4162        7000 :     rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
    4163        7000 :                                          estate->readonly_func, tcount);
    4164             : 
    4165             :     /*
    4166             :      * Check for error, and set FOUND if appropriate (for historical reasons
    4167             :      * we set FOUND only for certain query types).  Also Assert that we
    4168             :      * identified the statement type the same as SPI did.
    4169             :      */
    4170        6958 :     switch (rc)
    4171             :     {
    4172             :         case SPI_OK_SELECT:
    4173             :             Assert(!stmt->mod_stmt);
    4174        2192 :             exec_set_found(estate, (SPI_processed != 0));
    4175        2192 :             break;
    4176             : 
    4177             :         case SPI_OK_INSERT:
    4178             :         case SPI_OK_UPDATE:
    4179             :         case SPI_OK_DELETE:
    4180             :         case SPI_OK_INSERT_RETURNING:
    4181             :         case SPI_OK_UPDATE_RETURNING:
    4182             :         case SPI_OK_DELETE_RETURNING:
    4183             :             Assert(stmt->mod_stmt);
    4184        4682 :             exec_set_found(estate, (SPI_processed != 0));
    4185        4682 :             break;
    4186             : 
    4187             :         case SPI_OK_SELINTO:
    4188             :         case SPI_OK_UTILITY:
    4189             :             Assert(!stmt->mod_stmt);
    4190          82 :             break;
    4191             : 
    4192             :         case SPI_OK_REWRITTEN:
    4193             : 
    4194             :             /*
    4195             :              * The command was rewritten into another kind of command. It's
    4196             :              * not clear what FOUND would mean in that case (and SPI doesn't
    4197             :              * return the row count either), so just set it to false.  Note
    4198             :              * that we can't assert anything about mod_stmt here.
    4199             :              */
    4200           0 :             exec_set_found(estate, false);
    4201           0 :             break;
    4202             : 
    4203             :             /* Some SPI errors deserve specific error messages */
    4204             :         case SPI_ERROR_COPY:
    4205           0 :             ereport(ERROR,
    4206             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4207             :                      errmsg("cannot COPY to/from client in PL/pgSQL")));
    4208             :             break;
    4209             : 
    4210             :         case SPI_ERROR_TRANSACTION:
    4211           2 :             ereport(ERROR,
    4212             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4213             :                      errmsg("unsupported transaction command in PL/pgSQL")));
    4214             :             break;
    4215             : 
    4216             :         default:
    4217           0 :             elog(ERROR, "SPI_execute_plan_with_paramlist failed executing query \"%s\": %s",
    4218             :                  expr->query, SPI_result_code_string(rc));
    4219             :             break;
    4220             :     }
    4221             : 
    4222             :     /* All variants should save result info for GET DIAGNOSTICS */
    4223        6956 :     estate->eval_processed = SPI_processed;
    4224             : 
    4225             :     /* Process INTO if present */
    4226        6956 :     if (stmt->into)
    4227             :     {
    4228        2488 :         SPITupleTable *tuptab = SPI_tuptable;
    4229        2488 :         uint64      n = SPI_processed;
    4230             :         PLpgSQL_variable *target;
    4231             : 
    4232             :         /* If the statement did not return a tuple table, complain */
    4233        2488 :         if (tuptab == NULL)
    4234           0 :             ereport(ERROR,
    4235             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    4236             :                      errmsg("INTO used with a command that cannot return data")));
    4237             : 
    4238             :         /* Fetch target's datum entry */
    4239        2488 :         target = (PLpgSQL_variable *) estate->datums[stmt->target->dno];
    4240             : 
    4241             :         /*
    4242             :          * If SELECT ... INTO specified STRICT, and the query didn't find
    4243             :          * exactly one row, throw an error.  If STRICT was not specified, then
    4244             :          * allow the query to find any number of rows.
    4245             :          */
    4246        2488 :         if (n == 0)
    4247             :         {
    4248          38 :             if (stmt->strict)
    4249             :             {
    4250             :                 char       *errdetail;
    4251             : 
    4252           8 :                 if (estate->func->print_strict_params)
    4253           4 :                     errdetail = format_expr_params(estate, expr);
    4254             :                 else
    4255           4 :                     errdetail = NULL;
    4256             : 
    4257           8 :                 ereport(ERROR,
    4258             :                         (errcode(ERRCODE_NO_DATA_FOUND),
    4259             :                          errmsg("query returned no rows"),
    4260             :                          errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
    4261             :             }
    4262             :             /* set the target to NULL(s) */
    4263          30 :             exec_move_row(estate, target, NULL, tuptab->tupdesc);
    4264             :         }
    4265             :         else
    4266             :         {
    4267        2450 :             if (n > 1 && (stmt->strict || stmt->mod_stmt || too_many_rows_level))
    4268             :             {
    4269             :                 char       *errdetail;
    4270             :                 int         errlevel;
    4271             : 
    4272          32 :                 if (estate->func->print_strict_params)
    4273          12 :                     errdetail = format_expr_params(estate, expr);
    4274             :                 else
    4275          20 :                     errdetail = NULL;
    4276             : 
    4277          32 :                 errlevel = (stmt->strict || stmt->mod_stmt) ? ERROR : too_many_rows_level;
    4278             : 
    4279          32 :                 ereport(errlevel,
    4280             :                         (errcode(ERRCODE_TOO_MANY_ROWS),
    4281             :                          errmsg("query returned more than one row"),
    4282             :                          errdetail ? errdetail_internal("parameters: %s", errdetail) : 0,
    4283             :                          errhint("Make sure the query returns a single row, or use LIMIT 1.")));
    4284             :             }
    4285             :             /* Put the first result row into the target */
    4286        2422 :             exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc);
    4287             :         }
    4288             : 
    4289             :         /* Clean up */
    4290        2436 :         exec_eval_cleanup(estate);
    4291        2436 :         SPI_freetuptable(SPI_tuptable);
    4292             :     }
    4293             :     else
    4294             :     {
    4295             :         /* If the statement returned a tuple table, complain */
    4296        4468 :         if (SPI_tuptable != NULL)
    4297           0 :             ereport(ERROR,
    4298             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    4299             :                      errmsg("query has no destination for result data"),
    4300             :                      (rc == SPI_OK_SELECT) ? errhint("If you want to discard the results of a SELECT, use PERFORM instead.") : 0));
    4301             :     }
    4302             : 
    4303        6904 :     return PLPGSQL_RC_OK;
    4304             : }
    4305             : 
    4306             : 
    4307             : /* ----------
    4308             :  * exec_stmt_dynexecute         Execute a dynamic SQL query
    4309             :  *                  (possibly with INTO).
    4310             :  * ----------
    4311             :  */
    4312             : static int
    4313        6496 : exec_stmt_dynexecute(PLpgSQL_execstate *estate,
    4314             :                      PLpgSQL_stmt_dynexecute *stmt)
    4315             : {
    4316             :     Datum       query;
    4317             :     bool        isnull;
    4318             :     Oid         restype;
    4319             :     int32       restypmod;
    4320             :     char       *querystr;
    4321             :     int         exec_res;
    4322        6496 :     PreparedParamsData *ppd = NULL;
    4323        6496 :     MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
    4324             : 
    4325             :     /*
    4326             :      * First we evaluate the string expression after the EXECUTE keyword. Its
    4327             :      * result is the querystring we have to execute.
    4328             :      */
    4329        6496 :     query = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod);
    4330        6496 :     if (isnull)
    4331           0 :         ereport(ERROR,
    4332             :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    4333             :                  errmsg("query string argument of EXECUTE is null")));
    4334             : 
    4335             :     /* Get the C-String representation */
    4336        6496 :     querystr = convert_value_to_string(estate, query, restype);
    4337             : 
    4338             :     /* copy it into the stmt_mcontext before we clean up */
    4339        6496 :     querystr = MemoryContextStrdup(stmt_mcontext, querystr);
    4340             : 
    4341        6496 :     exec_eval_cleanup(estate);
    4342             : 
    4343             :     /*
    4344             :      * Execute the query without preparing a saved plan.
    4345             :      */
    4346        6496 :     if (stmt->params)
    4347             :     {
    4348         124 :         ppd = exec_eval_using_params(estate, stmt->params);
    4349         248 :         exec_res = SPI_execute_with_args(querystr,
    4350             :                                          ppd->nargs, ppd->types,
    4351         124 :                                          ppd->values, ppd->nulls,
    4352         124 :                                          estate->readonly_func, 0);
    4353             :     }
    4354             :     else
    4355        6372 :         exec_res = SPI_execute(querystr, estate->readonly_func, 0);
    4356             : 
    4357        6428 :     switch (exec_res)
    4358             :     {
    4359             :         case SPI_OK_SELECT:
    4360             :         case SPI_OK_INSERT:
    4361             :         case SPI_OK_UPDATE:
    4362             :         case SPI_OK_DELETE:
    4363             :         case SPI_OK_INSERT_RETURNING:
    4364             :         case SPI_OK_UPDATE_RETURNING:
    4365             :         case SPI_OK_DELETE_RETURNING:
    4366             :         case SPI_OK_UTILITY:
    4367             :         case SPI_OK_REWRITTEN:
    4368        6426 :             break;
    4369             : 
    4370             :         case 0:
    4371             : 
    4372             :             /*
    4373             :              * Also allow a zero return, which implies the querystring
    4374             :              * contained no commands.
    4375             :              */
    4376           0 :             break;
    4377             : 
    4378             :         case SPI_OK_SELINTO:
    4379             : 
    4380             :             /*
    4381             :              * We want to disallow SELECT INTO for now, because its behavior
    4382             :              * is not consistent with SELECT INTO in a normal plpgsql context.
    4383             :              * (We need to reimplement EXECUTE to parse the string as a
    4384             :              * plpgsql command, not just feed it to SPI_execute.)  This is not
    4385             :              * a functional limitation because CREATE TABLE AS is allowed.
    4386             :              */
    4387           0 :             ereport(ERROR,
    4388             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4389             :                      errmsg("EXECUTE of SELECT ... INTO is not implemented"),
    4390             :                      errhint("You might want to use EXECUTE ... INTO or EXECUTE CREATE TABLE ... AS instead.")));
    4391             :             break;
    4392             : 
    4393             :             /* Some SPI errors deserve specific error messages */
    4394             :         case SPI_ERROR_COPY:
    4395           0 :             ereport(ERROR,
    4396             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4397             :                      errmsg("cannot COPY to/from client in PL/pgSQL")));
    4398             :             break;
    4399             : 
    4400             :         case SPI_ERROR_TRANSACTION:
    4401           2 :             ereport(ERROR,
    4402             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4403             :                      errmsg("EXECUTE of transaction commands is not implemented")));
    4404             :             break;
    4405             : 
    4406             :         default:
    4407           0 :             elog(ERROR, "SPI_execute failed executing query \"%s\": %s",
    4408             :                  querystr, SPI_result_code_string(exec_res));
    4409             :             break;
    4410             :     }
    4411             : 
    4412             :     /* Save result info for GET DIAGNOSTICS */
    4413        6426 :     estate->eval_processed = SPI_processed;
    4414             : 
    4415             :     /* Process INTO if present */
    4416        6426 :     if (stmt->into)
    4417             :     {
    4418        2322 :         SPITupleTable *tuptab = SPI_tuptable;
    4419        2322 :         uint64      n = SPI_processed;
    4420             :         PLpgSQL_variable *target;
    4421             : 
    4422             :         /* If the statement did not return a tuple table, complain */
    4423        2322 :         if (tuptab == NULL)
    4424           0 :             ereport(ERROR,
    4425             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    4426             :                      errmsg("INTO used with a command that cannot return data")));
    4427             : 
    4428             :         /* Fetch target's datum entry */
    4429        2322 :         target = (PLpgSQL_variable *) estate->datums[stmt->target->dno];
    4430             : 
    4431             :         /*
    4432             :          * If SELECT ... INTO specified STRICT, and the query didn't find
    4433             :          * exactly one row, throw an error.  If STRICT was not specified, then
    4434             :          * allow the query to find any number of rows.
    4435             :          */
    4436        2322 :         if (n == 0)
    4437             :         {
    4438           8 :             if (stmt->strict)
    4439             :             {
    4440             :                 char       *errdetail;
    4441             : 
    4442           8 :                 if (estate->func->print_strict_params)
    4443           4 :                     errdetail = format_preparedparamsdata(estate, ppd);
    4444             :                 else
    4445           4 :                     errdetail = NULL;
    4446             : 
    4447           8 :                 ereport(ERROR,
    4448             :                         (errcode(ERRCODE_NO_DATA_FOUND),
    4449             :                          errmsg("query returned no rows"),
    4450             :                          errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
    4451             :             }
    4452             :             /* set the target to NULL(s) */
    4453           0 :             exec_move_row(estate, target, NULL, tuptab->tupdesc);
    4454             :         }
    4455             :         else
    4456             :         {
    4457        2314 :             if (n > 1 && stmt->strict)
    4458             :             {
    4459             :                 char       *errdetail;
    4460             : 
    4461          12 :                 if (estate->func->print_strict_params)
    4462           8 :                     errdetail = format_preparedparamsdata(estate, ppd);
    4463             :                 else
    4464           4 :                     errdetail = NULL;
    4465             : 
    4466          12 :                 ereport(ERROR,
    4467             :                         (errcode(ERRCODE_TOO_MANY_ROWS),
    4468             :                          errmsg("query returned more than one row"),
    4469             :                          errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
    4470             :             }
    4471             : 
    4472             :             /* Put the first result row into the target */
    4473        2302 :             exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc);
    4474             :         }
    4475             :         /* clean up after exec_move_row() */
    4476        2302 :         exec_eval_cleanup(estate);
    4477             :     }
    4478             :     else
    4479             :     {
    4480             :         /*
    4481             :          * It might be a good idea to raise an error if the query returned
    4482             :          * tuples that are being ignored, but historically we have not done
    4483             :          * that.
    4484             :          */
    4485             :     }
    4486             : 
    4487             :     /* Release any result from SPI_execute, as well as transient data */
    4488        6406 :     SPI_freetuptable(SPI_tuptable);
    4489        6406 :     MemoryContextReset(stmt_mcontext);
    4490             : 
    4491        6406 :     return PLPGSQL_RC_OK;
    4492             : }
    4493             : 
    4494             : 
    4495             : /* ----------
    4496             :  * exec_stmt_dynfors            Execute a dynamic query, assign each
    4497             :  *                  tuple to a record or row and
    4498             :  *                  execute a group of statements
    4499             :  *                  for it.
    4500             :  * ----------
    4501             :  */
    4502             : static int
    4503        2366 : exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
    4504             : {
    4505             :     Portal      portal;
    4506             :     int         rc;
    4507             : 
    4508        2366 :     portal = exec_dynquery_with_params(estate, stmt->query, stmt->params,
    4509             :                                        NULL, 0);
    4510             : 
    4511             :     /*
    4512             :      * Execute the loop
    4513             :      */
    4514        2366 :     rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, true);
    4515             : 
    4516             :     /*
    4517             :      * Close the implicit cursor
    4518             :      */
    4519        2366 :     SPI_cursor_close(portal);
    4520             : 
    4521        2366 :     return rc;
    4522             : }
    4523             : 
    4524             : 
    4525             : /* ----------
    4526             :  * exec_stmt_open           Execute an OPEN cursor statement
    4527             :  * ----------
    4528             :  */
    4529             : static int
    4530          84 : exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
    4531             : {
    4532             :     PLpgSQL_var *curvar;
    4533          84 :     MemoryContext stmt_mcontext = NULL;
    4534          84 :     char       *curname = NULL;
    4535             :     PLpgSQL_expr *query;
    4536             :     Portal      portal;
    4537             :     ParamListInfo paramLI;
    4538             : 
    4539             :     /* ----------
    4540             :      * Get the cursor variable and if it has an assigned name, check
    4541             :      * that it's not in use currently.
    4542             :      * ----------
    4543             :      */
    4544          84 :     curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
    4545          84 :     if (!curvar->isnull)
    4546             :     {
    4547             :         MemoryContext oldcontext;
    4548             : 
    4549             :         /* We only need stmt_mcontext to hold the cursor name string */
    4550          60 :         stmt_mcontext = get_stmt_mcontext(estate);
    4551          60 :         oldcontext = MemoryContextSwitchTo(stmt_mcontext);
    4552          60 :         curname = TextDatumGetCString(curvar->value);
    4553          60 :         MemoryContextSwitchTo(oldcontext);
    4554             : 
    4555          60 :         if (SPI_cursor_find(curname) != NULL)
    4556           0 :             ereport(ERROR,
    4557             :                     (errcode(ERRCODE_DUPLICATE_CURSOR),
    4558             :                      errmsg("cursor \"%s\" already in use", curname)));
    4559             :     }
    4560             : 
    4561             :     /* ----------
    4562             :      * Process the OPEN according to it's type.
    4563             :      * ----------
    4564             :      */
    4565          84 :     if (stmt->query != NULL)
    4566             :     {
    4567             :         /* ----------
    4568             :          * This is an OPEN refcursor FOR SELECT ...
    4569             :          *
    4570             :          * We just make sure the query is planned. The real work is
    4571             :          * done downstairs.
    4572             :          * ----------
    4573             :          */
    4574          24 :         query = stmt->query;
    4575          24 :         if (query->plan == NULL)
    4576          16 :             exec_prepare_plan(estate, query, stmt->cursor_options, true);
    4577             :     }
    4578          60 :     else if (stmt->dynquery != NULL)
    4579             :     {
    4580             :         /* ----------
    4581             :          * This is an OPEN refcursor FOR EXECUTE ...
    4582             :          * ----------
    4583             :          */
    4584          12 :         portal = exec_dynquery_with_params(estate,
    4585             :                                            stmt->dynquery,
    4586             :                                            stmt->params,
    4587             :                                            curname,
    4588             :                                            stmt->cursor_options);
    4589             : 
    4590             :         /*
    4591             :          * If cursor variable was NULL, store the generated portal name in it.
    4592             :          * Note: exec_dynquery_with_params already reset the stmt_mcontext, so
    4593             :          * curname is a dangling pointer here; but testing it for nullness is
    4594             :          * OK.
    4595             :          */
    4596          12 :         if (curname == NULL)
    4597          12 :             assign_text_var(estate, curvar, portal->name);
    4598             : 
    4599          12 :         return PLPGSQL_RC_OK;
    4600             :     }
    4601             :     else
    4602             :     {
    4603             :         /* ----------
    4604             :          * This is an OPEN cursor
    4605             :          *
    4606             :          * Note: parser should already have checked that statement supplies
    4607             :          * args iff cursor needs them, but we check again to be safe.
    4608             :          * ----------
    4609             :          */
    4610          48 :         if (stmt->argquery != NULL)
    4611             :         {
    4612             :             /* ----------
    4613             :              * OPEN CURSOR with args.  We fake a SELECT ... INTO ...
    4614             :              * statement to evaluate the args and put 'em into the
    4615             :              * internal row.
    4616             :              * ----------
    4617             :              */
    4618             :             PLpgSQL_stmt_execsql set_args;
    4619             : 
    4620          32 :             if (curvar->cursor_explicit_argrow < 0)
    4621           0 :                 ereport(ERROR,
    4622             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    4623             :                          errmsg("arguments given for cursor without arguments")));
    4624             : 
    4625          32 :             memset(&set_args, 0, sizeof(set_args));
    4626          32 :             set_args.cmd_type = PLPGSQL_STMT_EXECSQL;
    4627          32 :             set_args.lineno = stmt->lineno;
    4628          32 :             set_args.sqlstmt = stmt->argquery;
    4629          32 :             set_args.into = true;
    4630             :             /* XXX historically this has not been STRICT */
    4631          32 :             set_args.target = (PLpgSQL_variable *)
    4632          32 :                 (estate->datums[curvar->cursor_explicit_argrow]);
    4633             : 
    4634          32 :             if (exec_stmt_execsql(estate, &set_args) != PLPGSQL_RC_OK)
    4635           0 :                 elog(ERROR, "open cursor failed during argument processing");
    4636             :         }
    4637             :         else
    4638             :         {
    4639          16 :             if (curvar->cursor_explicit_argrow >= 0)
    4640           0 :                 ereport(ERROR,
    4641             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    4642             :                          errmsg("arguments required for cursor")));
    4643             :         }
    4644             : 
    4645          44 :         query = curvar->cursor_explicit_expr;
    4646          44 :         if (query->plan == NULL)
    4647          36 :             exec_prepare_plan(estate, query, curvar->cursor_options, true);
    4648             :     }
    4649             : 
    4650             :     /*
    4651             :      * Set up ParamListInfo for this query
    4652             :      */
    4653          68 :     paramLI = setup_param_list(estate, query);
    4654             : 
    4655             :     /*
    4656             :      * Open the cursor (the paramlist will get copied into the portal)
    4657             :      */
    4658          68 :     portal = SPI_cursor_open_with_paramlist(curname, query->plan,
    4659             :                                             paramLI,
    4660          68 :                                             estate->readonly_func);
    4661          68 :     if (portal == NULL)
    4662           0 :         elog(ERROR, "could not open cursor: %s",
    4663             :              SPI_result_code_string(SPI_result));
    4664             : 
    4665             :     /*
    4666             :      * If cursor variable was NULL, store the generated portal name in it
    4667             :      */
    4668          68 :     if (curname == NULL)
    4669          12 :         assign_text_var(estate, curvar, portal->name);
    4670             : 
    4671             :     /* If we had any transient data, clean it up */
    4672          68 :     exec_eval_cleanup(estate);
    4673          68 :     if (stmt_mcontext)
    4674          56 :         MemoryContextReset(stmt_mcontext);
    4675             : 
    4676          68 :     return PLPGSQL_RC_OK;
    4677             : }
    4678             : 
    4679             : 
    4680             : /* ----------
    4681             :  * exec_stmt_fetch          Fetch from a cursor into a target, or just
    4682             :  *                          move the current position of the cursor
    4683             :  * ----------
    4684             :  */
    4685             : static int
    4686         228 : exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
    4687             : {
    4688             :     PLpgSQL_var *curvar;
    4689         228 :     long        how_many = stmt->how_many;
    4690             :     SPITupleTable *tuptab;
    4691             :     Portal      portal;
    4692             :     char       *curname;
    4693             :     uint64      n;
    4694             :     MemoryContext oldcontext;
    4695             : 
    4696             :     /* ----------
    4697             :      * Get the portal of the cursor by name
    4698             :      * ----------
    4699             :      */
    4700         228 :     curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
    4701         228 :     if (curvar->isnull)
    4702           0 :         ereport(ERROR,
    4703             :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    4704             :                  errmsg("cursor variable \"%s\" is null", curvar->refname)));
    4705             : 
    4706             :     /* Use eval_mcontext for short-lived string */
    4707         228 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    4708         228 :     curname = TextDatumGetCString(curvar->value);
    4709         228 :     MemoryContextSwitchTo(oldcontext);
    4710             : 
    4711         228 :     portal = SPI_cursor_find(curname);
    4712         228 :     if (portal == NULL)
    4713           0 :         ereport(ERROR,
    4714             :                 (errcode(ERRCODE_UNDEFINED_CURSOR),
    4715             :                  errmsg("cursor \"%s\" does not exist", curname)));
    4716             : 
    4717             :     /* Calculate position for FETCH_RELATIVE or FETCH_ABSOLUTE */
    4718         228 :     if (stmt->expr)
    4719             :     {
    4720             :         bool        isnull;
    4721             : 
    4722             :         /* XXX should be doing this in LONG not INT width */
    4723          44 :         how_many = exec_eval_integer(estate, stmt->expr, &isnull);
    4724             : 
    4725          44 :         if (isnull)
    4726           0 :             ereport(ERROR,
    4727             :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    4728             :                      errmsg("relative or absolute cursor position is null")));
    4729             : 
    4730          44 :         exec_eval_cleanup(estate);
    4731             :     }
    4732             : 
    4733         228 :     if (!stmt->is_move)
    4734             :     {
    4735             :         PLpgSQL_variable *target;
    4736             : 
    4737             :         /* ----------
    4738             :          * Fetch 1 tuple from the cursor
    4739             :          * ----------
    4740             :          */
    4741         200 :         SPI_scroll_cursor_fetch(portal, stmt->direction, how_many);
    4742         196 :         tuptab = SPI_tuptable;
    4743         196 :         n = SPI_processed;
    4744             : 
    4745             :         /* ----------
    4746             :          * Set the target appropriately.
    4747             :          * ----------
    4748             :          */
    4749         196 :         target = (PLpgSQL_variable *) estate->datums[stmt->target->dno];
    4750         196 :         if (n == 0)
    4751          32 :             exec_move_row(estate, target, NULL, tuptab->tupdesc);
    4752             :         else
    4753         164 :             exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc);
    4754             : 
    4755         196 :         exec_eval_cleanup(estate);
    4756         196 :         SPI_freetuptable(tuptab);
    4757             :     }
    4758             :     else
    4759             :     {
    4760             :         /* Move the cursor */
    4761          28 :         SPI_scroll_cursor_move(portal, stmt->direction, how_many);
    4762          28 :         n = SPI_processed;
    4763             :     }
    4764             : 
    4765             :     /* Set the ROW_COUNT and the global FOUND variable appropriately. */
    4766         224 :     estate->eval_processed = n;
    4767         224 :     exec_set_found(estate, n != 0);
    4768             : 
    4769         224 :     return PLPGSQL_RC_OK;
    4770             : }
    4771             : 
    4772             : /* ----------
    4773             :  * exec_stmt_close          Close a cursor
    4774             :  * ----------
    4775             :  */
    4776             : static int
    4777          48 : exec_stmt_close(PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
    4778             : {
    4779             :     PLpgSQL_var *curvar;
    4780             :     Portal      portal;
    4781             :     char       *curname;
    4782             :     MemoryContext oldcontext;
    4783             : 
    4784             :     /* ----------
    4785             :      * Get the portal of the cursor by name
    4786             :      * ----------
    4787             :      */
    4788          48 :     curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
    4789          48 :     if (curvar->isnull)
    4790           0 :         ereport(ERROR,
    4791             :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    4792             :                  errmsg("cursor variable \"%s\" is null", curvar->refname)));
    4793             : 
    4794             :     /* Use eval_mcontext for short-lived string */
    4795          48 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    4796          48 :     curname = TextDatumGetCString(curvar->value);
    4797          48 :     MemoryContextSwitchTo(oldcontext);
    4798             : 
    4799          48 :     portal = SPI_cursor_find(curname);
    4800          48 :     if (portal == NULL)
    4801           0 :         ereport(ERROR,
    4802             :                 (errcode(ERRCODE_UNDEFINED_CURSOR),
    4803             :                  errmsg("cursor \"%s\" does not exist", curname)));
    4804             : 
    4805             :     /* ----------
    4806             :      * And close it.
    4807             :      * ----------
    4808             :      */
    4809          48 :     SPI_cursor_close(portal);
    4810             : 
    4811          48 :     return PLPGSQL_RC_OK;
    4812             : }
    4813             : 
    4814             : /*
    4815             :  * exec_stmt_commit
    4816             :  *
    4817             :  * Commit the transaction.
    4818             :  */
    4819             : static int
    4820        4110 : exec_stmt_commit(PLpgSQL_execstate *estate, PLpgSQL_stmt_commit *stmt)
    4821             : {
    4822        4110 :     if (stmt->chain)
    4823           4 :         SPI_commit_and_chain();
    4824             :     else
    4825             :     {
    4826        4106 :         SPI_commit();
    4827        4084 :         SPI_start_transaction();
    4828             :     }
    4829             : 
    4830        4088 :     estate->simple_eval_estate = NULL;
    4831        4088 :     plpgsql_create_econtext(estate);
    4832             : 
    4833        4088 :     return PLPGSQL_RC_OK;
    4834             : }
    4835             : 
    4836             : /*
    4837             :  * exec_stmt_rollback
    4838             :  *
    4839             :  * Abort the transaction.
    4840             :  */
    4841             : static int
    4842          72 : exec_stmt_rollback(PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
    4843             : {
    4844          72 :     if (stmt->chain)
    4845           4 :         SPI_rollback_and_chain();
    4846             :     else
    4847             :     {
    4848          68 :         SPI_rollback();
    4849          62 :         SPI_start_transaction();
    4850             :     }
    4851             : 
    4852          66 :     estate->simple_eval_estate = NULL;
    4853          66 :     plpgsql_create_econtext(estate);
    4854             : 
    4855          66 :     return PLPGSQL_RC_OK;
    4856             : }
    4857             : 
    4858             : /*
    4859             :  * exec_stmt_set
    4860             :  *
    4861             :  * Execute SET/RESET statement.
    4862             :  *
    4863             :  * We just parse and execute the statement normally, but we have to do it
    4864             :  * without setting a snapshot, for things like SET TRANSACTION.
    4865             :  */
    4866             : static int
    4867        4004 : exec_stmt_set(PLpgSQL_execstate *estate, PLpgSQL_stmt_set *stmt)
    4868             : {
    4869        4004 :     PLpgSQL_expr *expr = stmt->expr;
    4870             :     int         rc;
    4871             : 
    4872        4004 :     if (expr->plan == NULL)
    4873             :     {
    4874          48 :         exec_prepare_plan(estate, expr, 0, true);
    4875          48 :         expr->plan->no_snapshots = true;
    4876             :     }
    4877             : 
    4878        4004 :     rc = SPI_execute_plan(expr->plan, NULL, NULL, estate->readonly_func, 0);
    4879             : 
    4880        4000 :     if (rc != SPI_OK_UTILITY)
    4881           0 :         elog(ERROR, "SPI_execute_plan failed executing query \"%s\": %s",
    4882             :              expr->query, SPI_result_code_string(rc));
    4883             : 
    4884        4000 :     return PLPGSQL_RC_OK;
    4885             : }
    4886             : 
    4887             : /* ----------
    4888             :  * exec_assign_expr         Put an expression's result into a variable.
    4889             :  * ----------
    4890             :  */
    4891             : static void
    4892       19436 : exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target,
    4893             :                  PLpgSQL_expr *expr)
    4894             : {
    4895             :     Datum       value;
    4896             :     bool        isnull;
    4897             :     Oid         valtype;
    4898             :     int32       valtypmod;
    4899             : 
    4900             :     /*
    4901             :      * If first time through, create a plan for this expression, and then see
    4902             :      * if we can pass the target variable as a read-write parameter to the
    4903             :      * expression.  (This is a bit messy, but it seems cleaner than modifying
    4904             :      * the API of exec_eval_expr for the purpose.)
    4905             :      */
    4906       19436 :     if (expr->plan == NULL)
    4907             :     {
    4908        1832 :         exec_prepare_plan(estate, expr, 0, true);
    4909        1830 :         if (target->dtype == PLPGSQL_DTYPE_VAR)
    4910        1468 :             exec_check_rw_parameter(expr, target->dno);
    4911             :     }
    4912             : 
    4913       19434 :     value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
    4914       19366 :     exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
    4915       19244 :     exec_eval_cleanup(estate);
    4916       19244 : }
    4917             : 
    4918             : 
    4919             : /* ----------
    4920             :  * exec_assign_c_string     Put a C string into a text variable.
    4921             :  *
    4922             :  * We take a NULL pointer as signifying empty string, not SQL null.
    4923             :  *
    4924             :  * As with the underlying exec_assign_value, caller is expected to do
    4925             :  * exec_eval_cleanup later.
    4926             :  * ----------
    4927             :  */
    4928             : static void
    4929          94 : exec_assign_c_string(PLpgSQL_execstate *estate, PLpgSQL_datum *target,
    4930             :                      const char *str)
    4931             : {
    4932             :     text       *value;
    4933             :     MemoryContext oldcontext;
    4934             : 
    4935             :     /* Use eval_mcontext for short-lived text value */
    4936          94 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    4937          94 :     if (str != NULL)
    4938          94 :         value = cstring_to_text(str);
    4939             :     else
    4940           0 :         value = cstring_to_text("");
    4941          94 :     MemoryContextSwitchTo(oldcontext);
    4942             : 
    4943          94 :     exec_assign_value(estate, target, PointerGetDatum(value), false,
    4944             :                       TEXTOID, -1);
    4945          94 : }
    4946             : 
    4947             : 
    4948             : /* ----------
    4949             :  * exec_assign_value            Put a value into a target datum
    4950             :  *
    4951             :  * Note: in some code paths, this will leak memory in the eval_mcontext;
    4952             :  * we assume that will be cleaned up later by exec_eval_cleanup.  We cannot
    4953             :  * call exec_eval_cleanup here for fear of destroying the input Datum value.
    4954             :  * ----------
    4955             :  */
    4956             : static void
    4957       35620 : exec_assign_value(PLpgSQL_execstate *estate,
    4958             :                   PLpgSQL_datum *target,
    4959             :                   Datum value, bool isNull,
    4960             :                   Oid valtype, int32 valtypmod)
    4961             : {
    4962       35620 :     switch (target->dtype)
    4963             :     {
    4964             :         case PLPGSQL_DTYPE_VAR:
    4965             :         case PLPGSQL_DTYPE_PROMISE:
    4966             :             {
    4967             :                 /*
    4968             :                  * Target is a variable
    4969             :                  */
    4970       33504 :                 PLpgSQL_var *var = (PLpgSQL_var *) target;
    4971             :                 Datum       newvalue;
    4972             : 
    4973       67008 :                 newvalue = exec_cast_value(estate,
    4974             :                                            value,
    4975             :                                            &isNull,
    4976             :                                            valtype,
    4977             :                                            valtypmod,
    4978       33504 :                                            var->datatype->typoid,
    4979       33504 :                                            var->datatype->atttypmod);
    4980             : 
    4981       33440 :                 if (isNull && var->notnull)
    4982           8 :                     ereport(ERROR,
    4983             :                             (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    4984             :                              errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
    4985             :                                     var->refname)));
    4986             : 
    4987             :                 /*
    4988             :                  * If type is by-reference, copy the new value (which is
    4989             :                  * probably in the eval_mcontext) into the procedure's main
    4990             :                  * memory context.  But if it's a read/write reference to an
    4991             :                  * expanded object, no physical copy needs to happen; at most
    4992             :                  * we need to reparent the object's memory context.
    4993             :                  *
    4994             :                  * If it's an array, we force the value to be stored in R/W
    4995             :                  * expanded form.  This wins if the function later does, say,
    4996             :                  * a lot of array subscripting operations on the variable, and
    4997             :                  * otherwise might lose.  We might need to use a different
    4998             :                  * heuristic, but it's too soon to tell.  Also, are there
    4999             :                  * cases where it'd be useful to force non-array values into
    5000             :                  * expanded form?
    5001             :                  */
    5002       33432 :                 if (!var->datatype->typbyval && !isNull)
    5003             :                 {
    5004       26392 :                     if (var->datatype->typisarray &&
    5005        3970 :                         !VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(newvalue)))
    5006             :                     {
    5007             :                         /* array and not already R/W, so apply expand_array */
    5008        3670 :                         newvalue = expand_array(newvalue,
    5009             :                                                 estate->datum_context,
    5010             :                                                 NULL);
    5011             :                     }
    5012             :                     else
    5013             :                     {
    5014             :                         /* else transfer value if R/W, else just datumCopy */
    5015       18902 :                         newvalue = datumTransfer(newvalue,
    5016             :                                                  false,
    5017       18902 :                                                  var->datatype->typlen);
    5018             :                     }
    5019             :                 }
    5020             : 
    5021             :                 /*
    5022             :                  * Now free the old value, if any, and assign the new one. But
    5023             :                  * skip the assignment if old and new values are the same.
    5024             :                  * Note that for expanded objects, this test is necessary and
    5025             :                  * cannot reliably be made any earlier; we have to be looking
    5026             :                  * at the object's standard R/W pointer to be sure pointer
    5027             :                  * equality is meaningful.
    5028             :                  *
    5029             :                  * Also, if it's a promise variable, we should disarm the
    5030             :                  * promise in any case --- otherwise, assigning null to an
    5031             :                  * armed promise variable would fail to disarm the promise.
    5032             :                  */
    5033       33432 :                 if (var->value != newvalue || var->isnull || isNull)
    5034       32574 :                     assign_simple_var(estate, var, newvalue, isNull,
    5035       32574 :                                       (!var->datatype->typbyval && !isNull));
    5036             :                 else
    5037         858 :                     var->promise = PLPGSQL_PROMISE_NONE;
    5038       33432 :                 break;
    5039             :             }
    5040             : 
    5041             :         case PLPGSQL_DTYPE_ROW:
    5042             :             {
    5043             :                 /*
    5044             :                  * Target is a row variable
    5045             :                  */
    5046          28 :                 PLpgSQL_row *row = (PLpgSQL_row *) target;
    5047             : 
    5048          28 :                 if (isNull)
    5049             :                 {
    5050             :                     /* If source is null, just assign nulls to the row */
    5051           0 :                     exec_move_row(estate, (PLpgSQL_variable *) row,
    5052             :                                   NULL, NULL);
    5053             :                 }
    5054             :                 else
    5055             :                 {
    5056             :                     /* Source must be of RECORD or composite type */
    5057          28 :                     if (!type_is_rowtype(valtype))
    5058           0 :                         ereport(ERROR,
    5059             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    5060             :                                  errmsg("cannot assign non-composite value to a row variable")));
    5061          28 :                     exec_move_row_from_datum(estate, (PLpgSQL_variable *) row,
    5062             :                                              value);
    5063             :                 }
    5064          28 :                 break;
    5065             :             }
    5066             : 
    5067             :         case PLPGSQL_DTYPE_REC:
    5068             :             {
    5069             :                 /*
    5070             :                  * Target is a record variable
    5071             :                  */
    5072         296 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
    5073             : 
    5074         296 :                 if (isNull)
    5075             :                 {
    5076          26 :                     if (rec->notnull)
    5077           8 :                         ereport(ERROR,
    5078             :                                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    5079             :                                  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
    5080             :                                         rec->refname)));
    5081             : 
    5082             :                     /* Set variable to a simple NULL */
    5083          18 :                     exec_move_row(estate, (PLpgSQL_variable *) rec,
    5084             :                                   NULL, NULL);
    5085             :                 }
    5086             :                 else
    5087             :                 {
    5088             :                     /* Source must be of RECORD or composite type */
    5089         270 :                     if (!type_is_rowtype(valtype))
    5090           0 :                         ereport(ERROR,
    5091             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    5092             :                                  errmsg("cannot assign non-composite value to a record variable")));
    5093         270 :                     exec_move_row_from_datum(estate, (PLpgSQL_variable *) rec,
    5094             :                                              value);
    5095             :                 }
    5096         266 :                 break;
    5097             :             }
    5098             : 
    5099             :         case PLPGSQL_DTYPE_RECFIELD:
    5100             :             {
    5101             :                 /*
    5102             :                  * Target is a field of a record
    5103             :                  */
    5104        1708 :                 PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target;
    5105             :                 PLpgSQL_rec *rec;
    5106             :                 ExpandedRecordHeader *erh;
    5107             : 
    5108        1708 :                 rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    5109        1708 :                 erh = rec->erh;
    5110             : 
    5111             :                 /*
    5112             :                  * If record variable is NULL, instantiate it if it has a
    5113             :                  * named composite type, else complain.  (This won't change
    5114             :                  * the logical state of the record, but if we successfully
    5115             :                  * assign below, the unassigned fields will all become NULLs.)
    5116             :                  */
    5117        1708 :                 if (erh == NULL)
    5118             :                 {
    5119          56 :                     instantiate_empty_record_variable(estate, rec);
    5120          54 :                     erh = rec->erh;
    5121             :                 }
    5122             : 
    5123             :                 /*
    5124             :                  * Look up the field's properties if we have not already, or
    5125             :                  * if the tuple descriptor ID changed since last time.
    5126             :                  */
    5127        1706 :                 if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
    5128             :                 {
    5129         200 :                     if (!expanded_record_lookup_field(erh,
    5130         100 :                                                       recfield->fieldname,
    5131             :                                                       &recfield->finfo))
    5132           2 :                         ereport(ERROR,
    5133             :                                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    5134             :                                  errmsg("record \"%s\" has no field \"%s\"",
    5135             :                                         rec->refname, recfield->fieldname)));
    5136          98 :                     recfield->rectupledescid = erh->er_tupdesc_id;
    5137             :                 }
    5138             : 
    5139             :                 /* We don't support assignments to system columns. */
    5140        1704 :                 if (recfield->finfo.fnumber <= 0)
    5141           0 :                     ereport(ERROR,
    5142             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5143             :                              errmsg("cannot assign to system column \"%s\"",
    5144             :                                     recfield->fieldname)));
    5145             : 
    5146             :                 /* Cast the new value to the right type, if needed. */
    5147        1704 :                 value = exec_cast_value(estate,
    5148             :                                         value,
    5149             :                                         &isNull,
    5150             :                                         valtype,
    5151             :                                         valtypmod,
    5152             :                                         recfield->finfo.ftypeid,
    5153             :                                         recfield->finfo.ftypmod);
    5154             : 
    5155             :                 /* And assign it. */
    5156        1700 :                 expanded_record_set_field(erh, recfield->finfo.fnumber,
    5157             :                                           value, isNull, !estate->atomic);
    5158        1694 :                 break;
    5159             :             }
    5160             : 
    5161             :         case PLPGSQL_DTYPE_ARRAYELEM:
    5162             :             {
    5163             :                 /*
    5164             :                  * Target is an element of an array
    5165             :                  */
    5166             :                 PLpgSQL_arrayelem *arrayelem;
    5167             :                 int         nsubscripts;
    5168             :                 int         i;
    5169             :                 PLpgSQL_expr *subscripts[MAXDIM];
    5170             :                 int         subscriptvals[MAXDIM];
    5171             :                 Datum       oldarraydatum,
    5172             :                             newarraydatum,
    5173             :                             coerced_value;
    5174             :                 bool        oldarrayisnull;
    5175             :                 Oid         parenttypoid;
    5176             :                 int32       parenttypmod;
    5177             :                 SPITupleTable *save_eval_tuptable;
    5178             :                 MemoryContext oldcontext;
    5179             : 
    5180             :                 /*
    5181             :                  * We need to do subscript evaluation, which might require
    5182             :                  * evaluating general expressions; and the caller might have
    5183             :                  * done that too in order to prepare the input Datum.  We have
    5184             :                  * to save and restore the caller's SPI_execute result, if
    5185             :                  * any.
    5186             :                  */
    5187          84 :                 save_eval_tuptable = estate->eval_tuptable;
    5188          84 :                 estate->eval_tuptable = NULL;
    5189             : 
    5190             :                 /*
    5191             :                  * To handle constructs like x[1][2] := something, we have to
    5192             :                  * be prepared to deal with a chain of arrayelem datums. Chase
    5193             :                  * back to find the base array datum, and save the subscript
    5194             :                  * expressions as we go.  (We are scanning right to left here,
    5195             :                  * but want to evaluate the subscripts left-to-right to
    5196             :                  * minimize surprises.)  Note that arrayelem is left pointing
    5197             :                  * to the leftmost arrayelem datum, where we will cache the
    5198             :                  * array element type data.
    5199             :                  */
    5200          84 :                 nsubscripts = 0;
    5201             :                 do
    5202             :                 {
    5203          88 :                     arrayelem = (PLpgSQL_arrayelem *) target;
    5204          88 :                     if (nsubscripts >= MAXDIM)
    5205           0 :                         ereport(ERROR,
    5206             :                                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    5207             :                                  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
    5208             :                                         nsubscripts + 1, MAXDIM)));
    5209          88 :                     subscripts[nsubscripts++] = arrayelem->subscript;
    5210          88 :                     target = estate->datums[arrayelem->arrayparentno];
    5211          88 :                 } while (target->dtype == PLPGSQL_DTYPE_ARRAYELEM);
    5212             : 
    5213             :                 /* Fetch current value of array datum */
    5214          84 :                 exec_eval_datum(estate, target,
    5215             :                                 &parenttypoid, &parenttypmod,
    5216             :                                 &oldarraydatum, &oldarrayisnull);
    5217             : 
    5218             :                 /* Update cached type data if necessary */
    5219         122 :                 if (arrayelem->parenttypoid != parenttypoid ||
    5220          38 :                     arrayelem->parenttypmod != parenttypmod)
    5221             :                 {
    5222             :                     Oid         arraytypoid;
    5223          46 :                     int32       arraytypmod = parenttypmod;
    5224             :                     int16       arraytyplen;
    5225             :                     Oid         elemtypoid;
    5226             :                     int16       elemtyplen;
    5227             :                     bool        elemtypbyval;
    5228             :                     char        elemtypalign;
    5229             : 
    5230             :                     /* If target is domain over array, reduce to base type */
    5231          46 :                     arraytypoid = getBaseTypeAndTypmod(parenttypoid,
    5232             :                                                        &arraytypmod);
    5233             : 
    5234             :                     /* ... and identify the element type */
    5235          46 :                     elemtypoid = get_element_type(arraytypoid);
    5236          46 :                     if (!OidIsValid(elemtypoid))
    5237           0 :                         ereport(ERROR,
    5238             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    5239             :                                  errmsg("subscripted object is not an array")));
    5240             : 
    5241             :                     /* Collect needed data about the types */
    5242          46 :                     arraytyplen = get_typlen(arraytypoid);
    5243             : 
    5244          46 :                     get_typlenbyvalalign(elemtypoid,
    5245             :                                          &elemtyplen,
    5246             :                                          &elemtypbyval,
    5247             :                                          &elemtypalign);
    5248             : 
    5249             :                     /* Now safe to update the cached data */
    5250          46 :                     arrayelem->parenttypoid = parenttypoid;
    5251          46 :                     arrayelem->parenttypmod = parenttypmod;
    5252          46 :                     arrayelem->arraytypoid = arraytypoid;
    5253          46 :                     arrayelem->arraytypmod = arraytypmod;
    5254          46 :                     arrayelem->arraytyplen = arraytyplen;
    5255          46 :                     arrayelem->elemtypoid = elemtypoid;
    5256          46 :                     arrayelem->elemtyplen = elemtyplen;
    5257          46 :                     arrayelem->elemtypbyval = elemtypbyval;
    5258          46 :                     arrayelem->elemtypalign = elemtypalign;
    5259             :                 }
    5260             : 
    5261             :                 /*
    5262             :                  * Evaluate the subscripts, switch into left-to-right order.
    5263             :                  * Like the expression built by ExecInitSubscriptingRef(),
    5264             :                  * complain if any subscript is null.
    5265             :                  */
    5266         172 :                 for (i = 0; i < nsubscripts; i++)
    5267             :                 {
    5268             :                     bool        subisnull;
    5269             : 
    5270          88 :                     subscriptvals[i] =
    5271          88 :                         exec_eval_integer(estate,
    5272          88 :                                           subscripts[nsubscripts - 1 - i],
    5273             :                                           &subisnull);
    5274          88 :                     if (subisnull)
    5275           0 :                         ereport(ERROR,
    5276             :                                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    5277             :                                  errmsg("array subscript in assignment must not be null")));
    5278             : 
    5279             :                     /*
    5280             :                      * Clean up in case the subscript expression wasn't
    5281             :                      * simple. We can't do exec_eval_cleanup, but we can do
    5282             :                      * this much (which is safe because the integer subscript
    5283             :                      * value is surely pass-by-value), and we must do it in
    5284             :                      * case the next subscript expression isn't simple either.
    5285             :                      */
    5286          88 :                     if (estate->eval_tuptable != NULL)
    5287           8 :                         SPI_freetuptable(estate->eval_tuptable);
    5288          88 :                     estate->eval_tuptable = NULL;
    5289             :                 }
    5290             : 
    5291             :                 /* Now we can restore caller's SPI_execute result if any. */
    5292             :                 Assert(estate->eval_tuptable == NULL);
    5293          84 :                 estate->eval_tuptable = save_eval_tuptable;
    5294             : 
    5295             :                 /* Coerce source value to match array element type. */
    5296          84 :                 coerced_value = exec_cast_value(estate,
    5297             :                                                 value,
    5298             :                                                 &isNull,
    5299             :                                                 valtype,
    5300             :                                                 valtypmod,
    5301             :                                                 arrayelem->elemtypoid,
    5302             :                                                 arrayelem->arraytypmod);
    5303             : 
    5304             :                 /*
    5305             :                  * If the original array is null, cons up an empty array so
    5306             :                  * that the assignment can proceed; we'll end with a
    5307             :                  * one-element array containing just the assigned-to
    5308             :                  * subscript.  This only works for varlena arrays, though; for
    5309             :                  * fixed-length array types we skip the assignment.  We can't
    5310             :                  * support assignment of a null entry into a fixed-length
    5311             :                  * array, either, so that's a no-op too.  This is all ugly but
    5312             :                  * corresponds to the current behavior of execExpr*.c.
    5313             :                  */
    5314          72 :                 if (arrayelem->arraytyplen > 0 && /* fixed-length array? */
    5315           0 :                     (oldarrayisnull || isNull))
    5316           0 :                     return;
    5317             : 
    5318             :                 /* empty array, if any, and newarraydatum are short-lived */
    5319          72 :                 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    5320             : 
    5321          72 :                 if (oldarrayisnull)
    5322          24 :                     oldarraydatum = PointerGetDatum(construct_empty_array(arrayelem->elemtypoid));
    5323             : 
    5324             :                 /*
    5325             :                  * Build the modified array value.
    5326             :                  */
    5327         288 :                 newarraydatum = array_set_element(oldarraydatum,
    5328             :                                                   nsubscripts,
    5329             :                                                   subscriptvals,
    5330             :                                                   coerced_value,
    5331             :                                                   isNull,
    5332          72 :                                                   arrayelem->arraytyplen,
    5333          72 :                                                   arrayelem->elemtyplen,
    5334          72 :                                                   arrayelem->elemtypbyval,
    5335          72 :                                                   arrayelem->elemtypalign);
    5336             : 
    5337          72 :                 MemoryContextSwitchTo(oldcontext);
    5338             : 
    5339             :                 /*
    5340             :                  * Assign the new array to the base variable.  It's never NULL
    5341             :                  * at this point.  Note that if the target is a domain,
    5342             :                  * coercing the base array type back up to the domain will
    5343             :                  * happen within exec_assign_value.
    5344             :                  */
    5345          72 :                 exec_assign_value(estate, target,
    5346             :                                   newarraydatum,
    5347             :                                   false,
    5348             :                                   arrayelem->arraytypoid,
    5349             :                                   arrayelem->arraytypmod);
    5350          62 :                 break;
    5351             :             }
    5352             : 
    5353             :         default:
    5354           0 :             elog(ERROR, "unrecognized dtype: %d", target->dtype);
    5355             :     }
    5356             : }
    5357             : 
    5358             : /*
    5359             :  * exec_eval_datum              Get current value of a PLpgSQL_datum
    5360             :  *
    5361             :  * The type oid, typmod, value in Datum format, and null flag are returned.
    5362             :  *
    5363             :  * At present this doesn't handle PLpgSQL_expr or PLpgSQL_arrayelem datums;
    5364             :  * that's not needed because we never pass references to such datums to SPI.
    5365             :  *
    5366             :  * NOTE: the returned Datum points right at the stored value in the case of
    5367             :  * pass-by-reference datatypes.  Generally callers should take care not to
    5368             :  * modify the stored value.  Some callers intentionally manipulate variables
    5369             :  * referenced by R/W expanded pointers, though; it is those callers'
    5370             :  * responsibility that the results are semantically OK.
    5371             :  *
    5372             :  * In some cases we have to palloc a return value, and in such cases we put
    5373             :  * it into the estate's eval_mcontext.
    5374             :  */
    5375             : static void
    5376       14982 : exec_eval_datum(PLpgSQL_execstate *estate,
    5377             :                 PLpgSQL_datum *datum,
    5378             :                 Oid *typeid,
    5379             :                 int32 *typetypmod,
    5380             :                 Datum *value,
    5381             :                 bool *isnull)
    5382             : {
    5383             :     MemoryContext oldcontext;
    5384             : 
    5385       14982 :     switch (datum->dtype)
    5386             :     {
    5387             :         case PLPGSQL_DTYPE_PROMISE:
    5388             :             /* fulfill promise if needed, then handle like regular var */
    5389        9956 :             plpgsql_fulfill_promise(estate, (PLpgSQL_var *) datum);
    5390             : 
    5391             :             /* FALL THRU */
    5392             : 
    5393             :         case PLPGSQL_DTYPE_VAR:
    5394             :             {
    5395       12722 :                 PLpgSQL_var *var = (PLpgSQL_var *) datum;
    5396             : 
    5397       12722 :                 *typeid = var->datatype->typoid;
    5398       12722 :                 *typetypmod = var->datatype->atttypmod;
    5399       12722 :                 *value = var->value;
    5400       12722 :                 *isnull = var->isnull;
    5401       12722 :                 break;
    5402             :             }
    5403             : 
    5404             :         case PLPGSQL_DTYPE_ROW:
    5405             :             {
    5406          80 :                 PLpgSQL_row *row = (PLpgSQL_row *) datum;
    5407             :                 HeapTuple   tup;
    5408             : 
    5409             :                 /* We get here if there are multiple OUT parameters */
    5410          80 :                 if (!row->rowtupdesc)    /* should not happen */
    5411           0 :                     elog(ERROR, "row variable has no tupdesc");
    5412             :                 /* Make sure we have a valid type/typmod setting */
    5413          80 :                 BlessTupleDesc(row->rowtupdesc);
    5414          80 :                 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    5415          80 :                 tup = make_tuple_from_row(estate, row, row->rowtupdesc);
    5416          80 :                 if (tup == NULL)    /* should not happen */
    5417           0 :                     elog(ERROR, "row not compatible with its own tupdesc");
    5418          80 :                 *typeid = row->rowtupdesc->tdtypeid;
    5419          80 :                 *typetypmod = row->rowtupdesc->tdtypmod;
    5420          80 :                 *value = HeapTupleGetDatum(tup);
    5421          80 :                 *isnull = false;
    5422          80 :                 MemoryContextSwitchTo(oldcontext);
    5423          80 :                 break;
    5424             :             }
    5425             : 
    5426             :         case PLPGSQL_DTYPE_REC:
    5427             :             {
    5428        1192 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
    5429             : 
    5430        1192 :                 if (rec->erh == NULL)
    5431             :                 {
    5432             :                     /* Treat uninstantiated record as a simple NULL */
    5433          52 :                     *value = (Datum) 0;
    5434          52 :                     *isnull = true;
    5435             :                     /* Report variable's declared type */
    5436          52 :                     *typeid = rec->rectypeid;
    5437          52 :                     *typetypmod = -1;
    5438             :                 }
    5439             :                 else
    5440             :                 {
    5441        1140 :                     if (ExpandedRecordIsEmpty(rec->erh))
    5442             :                     {
    5443             :                         /* Empty record is also a NULL */
    5444          20 :                         *value = (Datum) 0;
    5445          20 :                         *isnull = true;
    5446             :                     }
    5447             :                     else
    5448             :                     {
    5449        1120 :                         *value = ExpandedRecordGetDatum(rec->erh);
    5450        1120 :                         *isnull = false;
    5451             :                     }
    5452        1140 :                     if (rec->rectypeid != RECORDOID)
    5453             :                     {
    5454             :                         /* Report variable's declared type, if not RECORD */
    5455         230 :                         *typeid = rec->rectypeid;
    5456         230 :                         *typetypmod = -1;
    5457             :                     }
    5458             :                     else
    5459             :                     {
    5460             :                         /* Report record's actual type if declared RECORD */
    5461         910 :                         *typeid = rec->erh->er_typeid;
    5462         910 :                         *typetypmod = rec->erh->er_typmod;
    5463             :                     }
    5464             :                 }
    5465        1192 :                 break;
    5466             :             }
    5467             : 
    5468             :         case PLPGSQL_DTYPE_RECFIELD:
    5469             :             {
    5470         988 :                 PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
    5471             :                 PLpgSQL_rec *rec;
    5472             :                 ExpandedRecordHeader *erh;
    5473             : 
    5474         988 :                 rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    5475         988 :                 erh = rec->erh;
    5476             : 
    5477             :                 /*
    5478             :                  * If record variable is NULL, instantiate it if it has a
    5479             :                  * named composite type, else complain.  (This won't change
    5480             :                  * the logical state of the record: it's still NULL.)
    5481             :                  */
    5482         988 :                 if (erh == NULL)
    5483             :                 {
    5484           0 :                     instantiate_empty_record_variable(estate, rec);
    5485           0 :                     erh = rec->erh;
    5486             :                 }
    5487             : 
    5488             :                 /*
    5489             :                  * Look up the field's properties if we have not already, or
    5490             :                  * if the tuple descriptor ID changed since last time.
    5491             :                  */
    5492         988 :                 if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
    5493             :                 {
    5494           8 :                     if (!expanded_record_lookup_field(erh,
    5495           4 :                                                       recfield->fieldname,
    5496             :                                                       &recfield->finfo))
    5497           0 :                         ereport(ERROR,
    5498             :                                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    5499             :                                  errmsg("record \"%s\" has no field \"%s\"",
    5500             :                                         rec->refname, recfield->fieldname)));
    5501           4 :                     recfield->rectupledescid = erh->er_tupdesc_id;
    5502             :                 }
    5503             : 
    5504             :                 /* Report type data. */
    5505         988 :                 *typeid = recfield->finfo.ftypeid;
    5506         988 :                 *typetypmod = recfield->finfo.ftypmod;
    5507             : 
    5508             :                 /* And fetch the field value. */
    5509         988 :                 *value = expanded_record_get_field(erh,
    5510             :                                                    recfield->finfo.fnumber,
    5511             :                                                    isnull);
    5512         988 :                 break;
    5513             :             }
    5514             : 
    5515             :         default:
    5516           0 :             elog(ERROR, "unrecognized dtype: %d", datum->dtype);
    5517             :     }
    5518       14982 : }
    5519             : 
    5520             : /*
    5521             :  * plpgsql_exec_get_datum_type              Get datatype of a PLpgSQL_datum
    5522             :  *
    5523             :  * This is the same logic as in exec_eval_datum, but we skip acquiring
    5524             :  * the actual value of the variable.  Also, needn't support DTYPE_ROW.
    5525             :  */
    5526             : Oid
    5527          40 : plpgsql_exec_get_datum_type(PLpgSQL_execstate *estate,
    5528             :                             PLpgSQL_datum *datum)
    5529             : {
    5530             :     Oid         typeid;
    5531             : 
    5532          40 :     switch (datum->dtype)
    5533             :     {
    5534             :         case PLPGSQL_DTYPE_VAR:
    5535             :         case PLPGSQL_DTYPE_PROMISE:
    5536             :             {
    5537          40 :                 PLpgSQL_var *var = (PLpgSQL_var *) datum;
    5538             : 
    5539          40 :                 typeid = var->datatype->typoid;
    5540          40 :                 break;
    5541             :             }
    5542             : 
    5543             :         case PLPGSQL_DTYPE_REC:
    5544             :             {
    5545           0 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
    5546             : 
    5547           0 :                 if (rec->erh == NULL || rec->rectypeid != RECORDOID)
    5548             :                 {
    5549             :                     /* Report variable's declared type */
    5550           0 :                     typeid = rec->rectypeid;
    5551             :                 }
    5552             :                 else
    5553             :                 {
    5554             :                     /* Report record's actual type if declared RECORD */
    5555           0 :                     typeid = rec->erh->er_typeid;
    5556             :                 }
    5557           0 :                 break;
    5558             :             }
    5559             : 
    5560             :         case PLPGSQL_DTYPE_RECFIELD:
    5561             :             {
    5562           0 :                 PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
    5563             :                 PLpgSQL_rec *rec;
    5564             : 
    5565           0 :                 rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    5566             : 
    5567             :                 /*
    5568             :                  * If record variable is NULL, instantiate it if it has a
    5569             :                  * named composite type, else complain.  (This won't change
    5570             :                  * the logical state of the record: it's still NULL.)
    5571             :                  */
    5572           0 :                 if (rec->erh == NULL)
    5573           0 :                     instantiate_empty_record_variable(estate, rec);
    5574             : 
    5575             :                 /*
    5576             :                  * Look up the field's properties if we have not already, or
    5577             :                  * if the tuple descriptor ID changed since last time.
    5578             :                  */
    5579           0 :                 if (unlikely(recfield->rectupledescid != rec->erh->er_tupdesc_id))
    5580             :                 {
    5581           0 :                     if (!expanded_record_lookup_field(rec->erh,
    5582           0 :                                                       recfield->fieldname,
    5583             :                                                       &recfield->finfo))
    5584           0 :                         ereport(ERROR,
    5585             :                                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    5586             :                                  errmsg("record \"%s\" has no field \"%s\"",
    5587             :                                         rec->refname, recfield->fieldname)));
    5588           0 :                     recfield->rectupledescid = rec->erh->er_tupdesc_id;
    5589             :                 }
    5590             : 
    5591           0 :                 typeid = recfield->finfo.ftypeid;
    5592           0 :                 break;
    5593             :             }
    5594             : 
    5595             :         default:
    5596           0 :             elog(ERROR, "unrecognized dtype: %d", datum->dtype);
    5597             :             typeid = InvalidOid;    /* keep compiler quiet */
    5598             :             break;
    5599             :     }
    5600             : 
    5601          40 :     return typeid;
    5602             : }
    5603             : 
    5604             : /*
    5605             :  * plpgsql_exec_get_datum_type_info         Get datatype etc of a PLpgSQL_datum
    5606             :  *
    5607             :  * An extended version of plpgsql_exec_get_datum_type, which also retrieves the
    5608             :  * typmod and collation of the datum.  Note however that we don't report the
    5609             :  * possibly-mutable typmod of RECORD values, but say -1 always.
    5610             :  */
    5611             : void
    5612       10538 : plpgsql_exec_get_datum_type_info(PLpgSQL_execstate *estate,
    5613             :                                  PLpgSQL_datum *datum,
    5614             :                                  Oid *typeId, int32 *typMod, Oid *collation)
    5615             : {
    5616       10538 :     switch (datum->dtype)
    5617             :     {
    5618             :         case PLPGSQL_DTYPE_VAR:
    5619             :         case PLPGSQL_DTYPE_PROMISE:
    5620             :             {
    5621        7936 :                 PLpgSQL_var *var = (PLpgSQL_var *) datum;
    5622             : 
    5623        7936 :                 *typeId = var->datatype->typoid;
    5624        7936 :                 *typMod = var->datatype->atttypmod;
    5625        7936 :                 *collation = var->datatype->collation;
    5626        7936 :                 break;
    5627             :             }
    5628             : 
    5629             :         case PLPGSQL_DTYPE_REC:
    5630             :             {
    5631         386 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
    5632             : 
    5633         386 :                 if (rec->erh == NULL || rec->rectypeid != RECORDOID)
    5634             :                 {
    5635             :                     /* Report variable's declared type */
    5636         100 :                     *typeId = rec->rectypeid;
    5637         100 :                     *typMod = -1;
    5638             :                 }
    5639             :                 else
    5640             :                 {
    5641             :                     /* Report record's actual type if declared RECORD */
    5642         286 :                     *typeId = rec->erh->er_typeid;
    5643             :                     /* do NOT return the mutable typmod of a RECORD variable */
    5644         286 :                     *typMod = -1;
    5645             :                 }
    5646             :                 /* composite types are never collatable */
    5647         386 :                 *collation = InvalidOid;
    5648         386 :                 break;
    5649             :             }
    5650             : 
    5651             :         case PLPGSQL_DTYPE_RECFIELD:
    5652             :             {
    5653        2216 :                 PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
    5654             :                 PLpgSQL_rec *rec;
    5655             : 
    5656        2216 :                 rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    5657             : 
    5658             :                 /*
    5659             :                  * If record variable is NULL, instantiate it if it has a
    5660             :                  * named composite type, else complain.  (This won't change
    5661             :                  * the logical state of the record: it's still NULL.)
    5662             :                  */
    5663        2216 :                 if (rec->erh == NULL)
    5664          10 :                     instantiate_empty_record_variable(estate, rec);
    5665             : 
    5666             :                 /*
    5667             :                  * Look up the field's properties if we have not already, or
    5668             :                  * if the tuple descriptor ID changed since last time.
    5669             :                  */
    5670        2214 :                 if (unlikely(recfield->rectupledescid != rec->erh->er_tupdesc_id))
    5671             :                 {
    5672        2700 :                     if (!expanded_record_lookup_field(rec->erh,
    5673        1350 :                                                       recfield->fieldname,
    5674             :                                                       &recfield->finfo))
    5675           6 :                         ereport(ERROR,
    5676             :                                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    5677             :                                  errmsg("record \"%s\" has no field \"%s\"",
    5678             :                                         rec->refname, recfield->fieldname)));
    5679        1344 :                     recfield->rectupledescid = rec->erh->er_tupdesc_id;
    5680             :                 }
    5681             : 
    5682        2208 :                 *typeId = recfield->finfo.ftypeid;
    5683        2208 :                 *typMod = recfield->finfo.ftypmod;
    5684        2208 :                 *collation = recfield->finfo.fcollation;
    5685        2208 :                 break;
    5686             :             }
    5687             : 
    5688             :         default:
    5689           0 :             elog(ERROR, "unrecognized dtype: %d", datum->dtype);
    5690             :             *typeId = InvalidOid;   /* keep compiler quiet */
    5691             :             *typMod = -1;
    5692             :             *collation = InvalidOid;
    5693             :             break;
    5694             :     }
    5695       10530 : }
    5696             : 
    5697             : /* ----------
    5698             :  * exec_eval_integer        Evaluate an expression, coerce result to int4
    5699             :  *
    5700             :  * Note we do not do exec_eval_cleanup here; the caller must do it at
    5701             :  * some later point.  (We do this because the caller may be holding the
    5702             :  * results of other, pass-by-reference, expression evaluations, such as
    5703             :  * an array value to be subscripted.)
    5704             :  * ----------
    5705             :  */
    5706             : static int
    5707         132 : exec_eval_integer(PLpgSQL_execstate *estate,
    5708             :                   PLpgSQL_expr *expr,
    5709             :                   bool *isNull)
    5710             : {
    5711             :     Datum       exprdatum;
    5712             :     Oid         exprtypeid;
    5713             :     int32       exprtypmod;
    5714             : 
    5715         132 :     exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
    5716         132 :     exprdatum = exec_cast_value(estate, exprdatum, isNull,
    5717             :                                 exprtypeid, exprtypmod,
    5718             :                                 INT4OID, -1);
    5719         132 :     return DatumGetInt32(exprdatum);
    5720             : }
    5721             : 
    5722             : /* ----------
    5723             :  * exec_eval_boolean        Evaluate an expression, coerce result to bool
    5724             :  *
    5725             :  * Note we do not do exec_eval_cleanup here; the caller must do it at
    5726             :  * some later point.
    5727             :  * ----------
    5728             :  */
    5729             : static bool
    5730       71160 : exec_eval_boolean(PLpgSQL_execstate *estate,
    5731             :                   PLpgSQL_expr *expr,
    5732             :                   bool *isNull)
    5733             : {
    5734             :     Datum       exprdatum;
    5735             :     Oid         exprtypeid;
    5736             :     int32       exprtypmod;
    5737             : 
    5738       71160 :     exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
    5739       71160 :     exprdatum = exec_cast_value(estate, exprdatum, isNull,
    5740             :                                 exprtypeid, exprtypmod,
    5741             :                                 BOOLOID, -1);
    5742       71160 :     return DatumGetBool(exprdatum);
    5743             : }
    5744             : 
    5745             : /* ----------
    5746             :  * exec_eval_expr           Evaluate an expression and return
    5747             :  *                  the result Datum, along with data type/typmod.
    5748             :  *
    5749             :  * NOTE: caller must do exec_eval_cleanup when done with the Datum.
    5750             :  * ----------
    5751             :  */
    5752             : static Datum
    5753      149440 : exec_eval_expr(PLpgSQL_execstate *estate,
    5754             :                PLpgSQL_expr *expr,
    5755             :                bool *isNull,
    5756             :                Oid *rettype,
    5757             :                int32 *rettypmod)
    5758             : {
    5759      149440 :     Datum       result = 0;
    5760             :     int         rc;
    5761             :     Form_pg_attribute attr;
    5762             : 
    5763             :     /*
    5764             :      * If first time through, create a plan for this expression.
    5765             :      */
    5766      149440 :     if (expr->plan == NULL)
    5767        7298 :         exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK, true);
    5768             : 
    5769             :     /*
    5770             :      * If this is a simple expression, bypass SPI and use the executor
    5771             :      * directly
    5772             :      */
    5773      149418 :     if (exec_eval_simple_expr(estate, expr,
    5774             :                               &result, isNull, rettype, rettypmod))
    5775      145278 :         return result;
    5776             : 
    5777             :     /*
    5778             :      * Else do it the hard way via exec_run_select
    5779             :      */
    5780        4046 :     rc = exec_run_select(estate, expr, 2, NULL);
    5781        4038 :     if (rc != SPI_OK_SELECT)
    5782           0 :         ereport(ERROR,
    5783             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    5784             :                  errmsg("query \"%s\" did not return data", expr->query)));
    5785             : 
    5786             :     /*
    5787             :      * Check that the expression returns exactly one column...
    5788             :      */
    5789        4038 :     if (estate->eval_tuptable->tupdesc->natts != 1)
    5790           0 :         ereport(ERROR,
    5791             :                 (errcode(ERRCODE_SYNTAX_ERROR),
    5792             :                  errmsg_plural("query \"%s\" returned %d column",
    5793             :                                "query \"%s\" returned %d columns",
    5794             :                                estate->eval_tuptable->tupdesc->natts,
    5795             :                                expr->query,
    5796             :                                estate->eval_tuptable->tupdesc->natts)));
    5797             : 
    5798             :     /*
    5799             :      * ... and get the column's datatype.
    5800             :      */
    5801        4038 :     attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
    5802        4038 :     *rettype = attr->atttypid;
    5803        4038 :     *rettypmod = attr->atttypmod;
    5804             : 
    5805             :     /*
    5806             :      * If there are no rows selected, the result is a NULL of that type.
    5807             :      */
    5808        4038 :     if (estate->eval_processed == 0)
    5809             :     {
    5810           2 :         *isNull = true;
    5811           2 :         return (Datum) 0;
    5812             :     }
    5813             : 
    5814             :     /*
    5815             :      * Check that the expression returned no more than one row.
    5816             :      */
    5817        4036 :     if (estate->eval_processed != 1)
    5818           0 :         ereport(ERROR,
    5819             :                 (errcode(ERRCODE_CARDINALITY_VIOLATION),
    5820             :                  errmsg("query \"%s\" returned more than one row",
    5821             :                         expr->query)));
    5822             : 
    5823             :     /*
    5824             :      * Return the single result Datum.
    5825             :      */
    5826        4036 :     return SPI_getbinval(estate->eval_tuptable->vals[0],
    5827        4036 :                          estate->eval_tuptable->tupdesc, 1, isNull);
    5828             : }
    5829             : 
    5830             : 
    5831             : /* ----------
    5832             :  * exec_run_select          Execute a select query
    5833             :  * ----------
    5834             :  */
    5835             : static int
    5836        7690 : exec_run_select(PLpgSQL_execstate *estate,
    5837             :                 PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
    5838             : {
    5839             :     ParamListInfo paramLI;
    5840             :     int         rc;
    5841             : 
    5842             :     /*
    5843             :      * On the first call for this expression generate the plan.
    5844             :      *
    5845             :      * If we don't need to return a portal, then we're just going to execute
    5846             :      * the query once, which means it's OK to use a parallel plan, even if the
    5847             :      * number of rows being fetched is limited.  If we do need to return a
    5848             :      * portal, the caller might do cursor operations, which parallel query
    5849             :      * can't support.
    5850             :      */
    5851        7690 :     if (expr->plan == NULL)
    5852         414 :         exec_prepare_plan(estate, expr,
    5853             :                           portalP == NULL ? CURSOR_OPT_PARALLEL_OK : 0, true);
    5854             : 
    5855             :     /*
    5856             :      * Set up ParamListInfo to pass to executor
    5857             :      */
    5858        7670 :     paramLI = setup_param_list(estate, expr);
    5859             : 
    5860             :     /*
    5861             :      * If a portal was requested, put the query and paramlist into the portal
    5862             :      */
    5863        7670 :     if (portalP != NULL)
    5864             :     {
    5865        1618 :         *portalP = SPI_cursor_open_with_paramlist(NULL, expr->plan,
    5866             :                                                   paramLI,
    5867        1618 :                                                   estate->readonly_func);
    5868        1618 :         if (*portalP == NULL)
    5869           0 :             elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
    5870             :                  expr->query, SPI_result_code_string(SPI_result));
    5871        1618 :         exec_eval_cleanup(estate);
    5872        1618 :         return SPI_OK_CURSOR;
    5873             :     }
    5874             : 
    5875             :     /*
    5876             :      * Execute the query
    5877             :      */
    5878        6052 :     rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
    5879        6052 :                                          estate->readonly_func, maxtuples);
    5880        5192 :     if (rc != SPI_OK_SELECT)
    5881           0 :         ereport(ERROR,
    5882             :                 (errcode(ERRCODE_SYNTAX_ERROR),
    5883             :                  errmsg("query \"%s\" is not a SELECT", expr->query)));
    5884             : 
    5885             :     /* Save query results for eventual cleanup */
    5886             :     Assert(estate->eval_tuptable == NULL);
    5887        5192 :     estate->eval_tuptable = SPI_tuptable;
    5888        5192 :     estate->eval_processed = SPI_processed;
    5889             : 
    5890        5192 :     return rc;
    5891             : }
    5892             : 
    5893             : 
    5894             : /*
    5895             :  * exec_for_query --- execute body of FOR loop for each row from a portal
    5896             :  *
    5897             :  * Used by exec_stmt_fors, exec_stmt_forc and exec_stmt_dynfors
    5898             :  */
    5899             : static int
    5900        3678 : exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
    5901             :                Portal portal, bool prefetch_ok)
    5902             : {
    5903             :     PLpgSQL_variable *var;
    5904             :     SPITupleTable *tuptab;
    5905        3678 :     bool        found = false;
    5906        3678 :     int         rc = PLPGSQL_RC_OK;
    5907        3678 :     uint64      previous_id = INVALID_TUPLEDESC_IDENTIFIER;
    5908        3678 :     bool        tupdescs_match = true;
    5909             :     uint64      n;
    5910             : 
    5911             :     /* Fetch loop variable's datum entry */
    5912        3678 :     var = (PLpgSQL_variable *) estate->datums[stmt->var->dno];
    5913             : 
    5914             :     /*
    5915             :      * Make sure the portal doesn't get closed by the user statements we
    5916             :      * execute.
    5917             :      */
    5918        3678 :     PinPortal(portal);
    5919             : 
    5920             :     /*
    5921             :      * Fetch the initial tuple(s).  If prefetching is allowed then we grab a
    5922             :      * few more rows to avoid multiple trips through executor startup
    5923             :      * overhead.
    5924             :      */
    5925        3678 :     SPI_cursor_fetch(portal, true, prefetch_ok ? 10 : 1);
    5926        3678 :     tuptab = SPI_tuptable;
    5927        3678 :     n = SPI_processed;
    5928             : 
    5929             :     /*
    5930             :      * If the query didn't return any rows, set the target to NULL and fall
    5931             :      * through with found = false.
    5932             :      */
    5933        3678 :     if (n == 0)
    5934             :     {
    5935         116 :         exec_move_row(estate, var, NULL, tuptab->tupdesc);
    5936         116 :         exec_eval_cleanup(estate);
    5937             :     }
    5938             :     else
    5939        3562 :         found = true;           /* processed at least one tuple */
    5940             : 
    5941             :     /*
    5942             :      * Now do the loop
    5943             :      */
    5944       10790 :     while (n > 0)
    5945             :     {
    5946             :         uint64      i;
    5947             : 
    5948       17746 :         for (i = 0; i < n; i++)
    5949             :         {
    5950             :             /*
    5951             :              * Assign the tuple to the target.  Here, because we know that all
    5952             :              * loop iterations should be assigning the same tupdesc, we can
    5953             :              * optimize away repeated creations of expanded records with
    5954             :              * identical tupdescs.  Testing for changes of er_tupdesc_id is
    5955             :              * reliable even if the loop body contains assignments that
    5956             :              * replace the target's value entirely, because it's assigned from
    5957             :              * a process-global counter.  The case where the tupdescs don't
    5958             :              * match could possibly be handled more efficiently than this
    5959             :              * coding does, but it's not clear extra effort is worthwhile.
    5960             :              */
    5961       14312 :             if (var->dtype == PLPGSQL_DTYPE_REC)
    5962             :             {
    5963        2144 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) var;
    5964             : 
    5965        3914 :                 if (rec->erh &&
    5966        3530 :                     rec->erh->er_tupdesc_id == previous_id &&
    5967             :                     tupdescs_match)
    5968             :                 {
    5969             :                     /* Only need to assign a new tuple value */
    5970        1750 :                     expanded_record_set_tuple(rec->erh, tuptab->vals[i],
    5971        1750 :                                               true, !estate->atomic);
    5972             :                 }
    5973             :                 else
    5974             :                 {
    5975             :                     /*
    5976             :                      * First time through, or var's tupdesc changed in loop,
    5977             :                      * or we have to do it the hard way because type coercion
    5978             :                      * is needed.
    5979             :                      */
    5980         788 :                     exec_move_row(estate, var,
    5981         394 :                                   tuptab->vals[i], tuptab->tupdesc);
    5982             : 
    5983             :                     /*
    5984             :                      * Check to see if physical assignment is OK next time.
    5985             :                      * Once the tupdesc comparison has failed once, we don't
    5986             :                      * bother rechecking in subsequent loop iterations.
    5987             :                      */
    5988         392 :                     if (tupdescs_match)
    5989             :                     {
    5990         384 :                         tupdescs_match =
    5991         400 :                             (rec->rectypeid == RECORDOID ||
    5992         400 :                              rec->rectypeid == tuptab->tupdesc->tdtypeid ||
    5993          16 :                              compatible_tupdescs(tuptab->tupdesc,
    5994             :                                                  expanded_record_get_tupdesc(rec->erh)));
    5995             :                     }
    5996         392 :                     previous_id = rec->erh->er_tupdesc_id;
    5997             :                 }
    5998             :             }
    5999             :             else
    6000       12168 :                 exec_move_row(estate, var, tuptab->vals[i], tuptab->tupdesc);
    6001             : 
    6002       14308 :             exec_eval_cleanup(estate);
    6003             : 
    6004             :             /*
    6005             :              * Execute the statements
    6006             :              */
    6007       14308 :             rc = exec_stmts(estate, stmt->body);
    6008             : 
    6009       14284 :             LOOP_RC_PROCESSING(stmt->label, goto loop_exit);
    6010             :         }
    6011             : 
    6012        3434 :         SPI_freetuptable(tuptab);
    6013             : 
    6014             :         /*
    6015             :          * Fetch more tuples.  If prefetching is allowed, grab 50 at a time.
    6016             :          */
    6017        3434 :         SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
    6018        3434 :         tuptab = SPI_tuptable;
    6019        3434 :         n = SPI_processed;
    6020             :     }
    6021             : 
    6022             : loop_exit:
    6023             : 
    6024             :     /*
    6025             :      * Release last group of tuples (if any)
    6026             :      */
    6027        3650 :     SPI_freetuptable(tuptab);
    6028             : 
    6029        3650 :     UnpinPortal(portal);
    6030             : 
    6031             :     /*
    6032             :      * Set the FOUND variable to indicate the result of executing the loop
    6033             :      * (namely, whether we looped one or more times). This must be set last so
    6034             :      * that it does not interfere with the value of the FOUND variable inside
    6035             :      * the loop processing itself.
    6036             :      */
    6037        3650 :     exec_set_found(estate, found);
    6038             : 
    6039        3650 :     return rc;
    6040             : }
    6041             : 
    6042             : 
    6043             : /* ----------
    6044             :  * exec_eval_simple_expr -      Evaluate a simple expression returning
    6045             :  *                              a Datum by directly calling ExecEvalExpr().
    6046             :  *
    6047             :  * If successful, store results into *result, *isNull, *rettype, *rettypmod
    6048             :  * and return true.  If the expression cannot be handled by simple evaluation,
    6049             :  * return false.
    6050             :  *
    6051             :  * Because we only store one execution tree for a simple expression, we
    6052             :  * can't handle recursion cases.  So, if we see the tree is already busy
    6053             :  * with an evaluation in the current xact, we just return false and let the
    6054             :  * caller run the expression the hard way.  (Other alternatives such as
    6055             :  * creating a new tree for a recursive call either introduce memory leaks,
    6056             :  * or add enough bookkeeping to be doubtful wins anyway.)  Another case that
    6057             :  * is covered by the expr_simple_in_use test is where a previous execution
    6058             :  * of the tree was aborted by an error: the tree may contain bogus state
    6059             :  * so we dare not re-use it.
    6060             :  *
    6061             :  * It is possible that we'd need to replan a simple expression; for example,
    6062             :  * someone might redefine a SQL function that had been inlined into the simple
    6063             :  * expression.  That cannot cause a simple expression to become non-simple (or
    6064             :  * vice versa), but we do have to handle replacing the expression tree.
    6065             :  * Fortunately it's normally inexpensive to call SPI_plan_get_cached_plan for
    6066             :  * a simple expression.
    6067             :  *
    6068             :  * Note: if pass-by-reference, the result is in the eval_mcontext.
    6069             :  * It will be freed when exec_eval_cleanup is done.
    6070             :  * ----------
    6071             :  */
    6072             : static bool
    6073      149418 : exec_eval_simple_expr(PLpgSQL_execstate *estate,
    6074             :                       PLpgSQL_expr *expr,
    6075             :                       Datum *result,
    6076             :                       bool *isNull,
    6077             :                       Oid *rettype,
    6078             :                       int32 *rettypmod)
    6079             : {
    6080      149418 :     ExprContext *econtext = estate->eval_econtext;
    6081      149418 :     LocalTransactionId curlxid = MyProc->lxid;
    6082             :     CachedPlan *cplan;
    6083             :     void       *save_setup_arg;
    6084             :     MemoryContext oldcontext;
    6085             : 
    6086             :     /*
    6087             :      * Forget it if expression wasn't simple before.
    6088             :      */
    6089      149418 :     if (expr->expr_simple_expr == NULL)
    6090        3702 :         return false;
    6091             : 
    6092             :     /*
    6093             :      * If expression is in use in current xact, don't touch it.
    6094             :      */
    6095      145716 :     if (expr->expr_simple_in_use && expr->expr_simple_lxid == curlxid)
    6096         344 :         return false;
    6097             : 
    6098             :     /*
    6099             :      * Revalidate cached plan, so that we will notice if it became stale. (We
    6100             :      * need to hold a refcount while using the plan, anyway.)  If replanning
    6101             :      * is needed, do that work in the eval_mcontext.
    6102             :      */
    6103      145372 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    6104      145372 :     cplan = SPI_plan_get_cached_plan(expr->plan);
    6105      145372 :     MemoryContextSwitchTo(oldcontext);
    6106             : 
    6107             :     /*
    6108             :      * We can't get a failure here, because the number of CachedPlanSources in
    6109             :      * the SPI plan can't change from what exec_simple_check_plan saw; it's a
    6110             :      * property of the raw parsetree generated from the query text.
    6111             :      */
    6112             :     Assert(cplan != NULL);
    6113             : 
    6114             :     /* If it got replanned, update our copy of the simple expression */
    6115      145372 :     if (cplan->generation != expr->expr_simple_generation)
    6116             :     {
    6117        1696 :         exec_save_simple_expr(expr, cplan);
    6118             :         /* better recheck r/w safety, as it could change due to inlining */
    6119        1696 :         if (expr->rwparam >= 0)
    6120           0 :             exec_check_rw_parameter(expr, expr->rwparam);
    6121             :     }
    6122             : 
    6123             :     /*
    6124             :      * Pass back previously-determined result type.
    6125             :      */
    6126      145372 :     *rettype = expr->expr_simple_type;
    6127      145372 :     *rettypmod = expr->expr_simple_typmod;
    6128             : 
    6129             :     /*
    6130             :      * Set up ParamListInfo to pass to executor.  For safety, save and restore
    6131             :      * estate->paramLI->parserSetupArg around our use of the param list.
    6132             :      */
    6133      145372 :     save_setup_arg = estate->paramLI->parserSetupArg;
    6134             : 
    6135      145372 :     econtext->ecxt_param_list_info = setup_param_list(estate, expr);
    6136             : 
    6137             :     /*
    6138             :      * Prepare the expression for execution, if it's not been done already in
    6139             :      * the current transaction.  (This will be forced to happen if we called
    6140             :      * exec_save_simple_expr above.)
    6141             :      */
    6142      145372 :     if (expr->expr_simple_lxid != curlxid)
    6143             :     {
    6144       35584 :         oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
    6145       35584 :         expr->expr_simple_state =
    6146       35584 :             ExecInitExprWithParams(expr->expr_simple_expr,
    6147             :                                    econtext->ecxt_param_list_info);
    6148       35584 :         expr->expr_simple_in_use = false;
    6149       35584 :         expr->expr_simple_lxid = curlxid;
    6150       35584 :         MemoryContextSwitchTo(oldcontext);
    6151             :     }
    6152             : 
    6153             :     /*
    6154             :      * We have to do some of the things SPI_execute_plan would do, in
    6155             :      * particular advance the snapshot if we are in a non-read-only function.
    6156             :      * Without this, stable functions within the expression would fail to see
    6157             :      * updates made so far by our own function.
    6158             :      */
    6159      145372 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    6160      145372 :     if (!estate->readonly_func)
    6161             :     {
    6162       80706 :         CommandCounterIncrement();
    6163       80706 :         PushActiveSnapshot(GetTransactionSnapshot());
    6164             :     }
    6165             : 
    6166             :     /*
    6167             :      * Mark expression as busy for the duration of the ExecEvalExpr call.
    6168             :      */
    6169      145372 :     expr->expr_simple_in_use = true;
    6170             : 
    6171             :     /*
    6172             :      * Finally we can call the executor to evaluate the expression
    6173             :      */
    6174      145372 :     *result = ExecEvalExpr(expr->expr_simple_state,
    6175             :                            econtext,
    6176             :                            isNull);
    6177             : 
    6178             :     /* Assorted cleanup */
    6179      145278 :     expr->expr_simple_in_use = false;
    6180             : 
    6181      145278 :     econtext->ecxt_param_list_info = NULL;
    6182             : 
    6183      145278 :     estate->paramLI->parserSetupArg = save_setup_arg;
    6184             : 
    6185      145278 :     if (!estate->readonly_func)
    6186       80616 :         PopActiveSnapshot();
    6187             : 
    6188      145278 :     MemoryContextSwitchTo(oldcontext);
    6189             : 
    6190             :     /*
    6191             :      * Now we can release our refcount on the cached plan.
    6192             :      */
    6193      145278 :     ReleaseCachedPlan(cplan, true);
    6194             : 
    6195             :     /*
    6196             :      * That's it.
    6197             :      */
    6198      145278 :     return true;
    6199             : }
    6200             : 
    6201             : 
    6202             : /*
    6203             :  * Create a ParamListInfo to pass to SPI
    6204             :  *
    6205             :  * We use a single ParamListInfo struct for all SPI calls made from this
    6206             :  * estate; it contains no per-param data, just hook functions, so it's
    6207             :  * effectively read-only for SPI.
    6208             :  *
    6209             :  * An exception from pure read-only-ness is that the parserSetupArg points
    6210             :  * to the specific PLpgSQL_expr being evaluated.  This is not an issue for
    6211             :  * statement-level callers, but lower-level callers must save and restore
    6212             :  * estate->paramLI->parserSetupArg just in case there's an active evaluation
    6213             :  * at an outer call level.  (A plausible alternative design would be to
    6214             :  * create a ParamListInfo struct for each PLpgSQL_expr, but for the moment
    6215             :  * that seems like a waste of memory.)
    6216             :  */
    6217             : static ParamListInfo
    6218      160198 : setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
    6219             : {
    6220             :     ParamListInfo paramLI;
    6221             : 
    6222             :     /*
    6223             :      * We must have created the SPIPlan already (hence, query text has been
    6224             :      * parsed/analyzed at least once); else we cannot rely on expr->paramnos.
    6225             :      */
    6226             :     Assert(expr->plan != NULL);
    6227             : 
    6228             :     /*
    6229             :      * We only need a ParamListInfo if the expression has parameters.  In
    6230             :      * principle we should test with bms_is_empty(), but we use a not-null
    6231             :      * test because it's faster.  In current usage bits are never removed from
    6232             :      * expr->paramnos, only added, so this test is correct anyway.
    6233             :      */
    6234      160198 :     if (expr->paramnos)
    6235             :     {
    6236             :         /* Use the common ParamListInfo */
    6237      120766 :         paramLI = estate->paramLI;
    6238             : 
    6239             :         /*
    6240             :          * Set up link to active expr where the hook functions can find it.
    6241             :          * Callers must save and restore parserSetupArg if there is any chance
    6242             :          * that they are interrupting an active use of parameters.
    6243             :          */
    6244      120766 :         paramLI->parserSetupArg = (void *) expr;
    6245             : 
    6246             :         /*
    6247             :          * Also make sure this is set before parser hooks need it.  There is
    6248             :          * no need to save and restore, since the value is always correct once
    6249             :          * set.  (Should be set already, but let's be sure.)
    6250             :          */
    6251      120766 :         expr->func = estate->func;
    6252             :     }
    6253             :     else
    6254             :     {
    6255             :         /*
    6256             :          * Expression requires no parameters.  Be sure we represent this case
    6257             :          * as a NULL ParamListInfo, so that plancache.c knows there is no
    6258             :          * point in a custom plan.
    6259             :          */
    6260       39432 :         paramLI = NULL;
    6261             :     }
    6262      160198 :     return paramLI;
    6263             : }
    6264             : 
    6265             : /*
    6266             :  * plpgsql_param_fetch      paramFetch callback for dynamic parameter fetch
    6267             :  *
    6268             :  * We always use the caller's workspace to construct the returned struct.
    6269             :  *
    6270             :  * Note: this is no longer used during query execution.  It is used during
    6271             :  * planning (with speculative == true) and when the ParamListInfo we supply
    6272             :  * to the executor is copied into a cursor portal or transferred to a
    6273             :  * parallel child process.
    6274             :  */
    6275             : static ParamExternData *
    6276        7274 : plpgsql_param_fetch(ParamListInfo params,
    6277             :                     int paramid, bool speculative,
    6278             :                     ParamExternData *prm)
    6279             : {
    6280             :     int         dno;
    6281             :     PLpgSQL_execstate *estate;
    6282             :     PLpgSQL_expr *expr;
    6283             :     PLpgSQL_datum *datum;
    6284        7274 :     bool        ok = true;
    6285             :     int32       prmtypmod;
    6286             : 
    6287             :     /* paramid's are 1-based, but dnos are 0-based */
    6288        7274 :     dno = paramid - 1;
    6289             :     Assert(dno >= 0 && dno < params->numParams);
    6290             : 
    6291             :     /* fetch back the hook data */
    6292        7274 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6293        7274 :     expr = (PLpgSQL_expr *) params->parserSetupArg;
    6294             :     Assert(params->numParams == estate->ndatums);
    6295             : 
    6296             :     /* now we can access the target datum */
    6297        7274 :     datum = estate->datums[dno];
    6298             : 
    6299             :     /*
    6300             :      * Since copyParamList() or SerializeParamList() will try to materialize
    6301             :      * every single parameter slot, it's important to return a dummy param
    6302             :      * when asked for a datum that's not supposed to be used by this SQL
    6303             :      * expression.  Otherwise we risk failures in exec_eval_datum(), or
    6304             :      * copying a lot more data than necessary.
    6305             :      */
    6306        7274 :     if (!bms_is_member(dno, expr->paramnos))
    6307        3914 :         ok = false;
    6308             : 
    6309             :     /*
    6310             :      * If the access is speculative, we prefer to return no data rather than
    6311             :      * to fail in exec_eval_datum().  Check the likely failure cases.
    6312             :      */
    6313        3360 :     else if (speculative)
    6314             :     {
    6315        2426 :         switch (datum->dtype)
    6316             :         {
    6317             :             case PLPGSQL_DTYPE_VAR:
    6318             :             case PLPGSQL_DTYPE_PROMISE:
    6319             :                 /* always safe */
    6320        1454 :                 break;
    6321             : 
    6322             :             case PLPGSQL_DTYPE_ROW:
    6323             :                 /* should be safe in all interesting cases */
    6324           0 :                 break;
    6325             : 
    6326             :             case PLPGSQL_DTYPE_REC:
    6327             :                 /* always safe (might return NULL, that's fine) */
    6328           8 :                 break;
    6329             : 
    6330             :             case PLPGSQL_DTYPE_RECFIELD:
    6331             :                 {
    6332         964 :                     PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
    6333             :                     PLpgSQL_rec *rec;
    6334             : 
    6335         964 :                     rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    6336             : 
    6337             :                     /*
    6338             :                      * If record variable is NULL, don't risk anything.
    6339             :                      */
    6340         964 :                     if (rec->erh == NULL)
    6341           0 :                         ok = false;
    6342             : 
    6343             :                     /*
    6344             :                      * Look up the field's properties if we have not already,
    6345             :                      * or if the tuple descriptor ID changed since last time.
    6346             :                      */
    6347         964 :                     else if (unlikely(recfield->rectupledescid != rec->erh->er_tupdesc_id))
    6348             :                     {
    6349           4 :                         if (expanded_record_lookup_field(rec->erh,
    6350           2 :                                                          recfield->fieldname,
    6351             :                                                          &recfield->finfo))
    6352           2 :                             recfield->rectupledescid = rec->erh->er_tupdesc_id;
    6353             :                         else
    6354           0 :                             ok = false;
    6355             :                     }
    6356         964 :                     break;
    6357             :                 }
    6358             : 
    6359             :             default:
    6360           0 :                 ok = false;
    6361           0 :                 break;
    6362             :         }
    6363             :     }
    6364             : 
    6365             :     /* Return "no such parameter" if not ok */
    6366        7274 :     if (!ok)
    6367             :     {
    6368        3914 :         prm->value = (Datum) 0;
    6369        3914 :         prm->isnull = true;
    6370        3914 :         prm->pflags = 0;
    6371        3914 :         prm->ptype = InvalidOid;
    6372        3914 :         return prm;
    6373             :     }
    6374             : 
    6375             :     /* OK, evaluate the value and store into the return struct */
    6376        3360 :     exec_eval_datum(estate, datum,
    6377             :                     &prm->ptype, &prmtypmod,
    6378             :                     &prm->value, &prm->isnull);
    6379             :     /* We can always mark params as "const" for executor's purposes */
    6380        3360 :     prm->pflags = PARAM_FLAG_CONST;
    6381             : 
    6382             :     /*
    6383             :      * If it's a read/write expanded datum, convert reference to read-only,
    6384             :      * unless it's safe to pass as read-write.
    6385             :      */
    6386        3360 :     if (dno != expr->rwparam)
    6387             :     {
    6388        3360 :         if (datum->dtype == PLPGSQL_DTYPE_VAR)
    6389        2316 :             prm->value = MakeExpandedObjectReadOnly(prm->value,
    6390             :                                                     prm->isnull,
    6391             :                                                     ((PLpgSQL_var *) datum)->datatype->typlen);
    6392        1044 :         else if (datum->dtype == PLPGSQL_DTYPE_REC)
    6393           8 :             prm->value = MakeExpandedObjectReadOnly(prm->value,
    6394             :                                                     prm->isnull,
    6395             :                                                     -1);
    6396             :     }
    6397             : 
    6398        3360 :     return prm;
    6399             : }
    6400             : 
    6401             : /*
    6402             :  * plpgsql_param_compile        paramCompile callback for plpgsql parameters
    6403             :  */
    6404             : static void
    6405       50144 : plpgsql_param_compile(ParamListInfo params, Param *param,
    6406             :                       ExprState *state,
    6407             :                       Datum *resv, bool *resnull)
    6408             : {
    6409             :     PLpgSQL_execstate *estate;
    6410             :     PLpgSQL_expr *expr;
    6411             :     int         dno;
    6412             :     PLpgSQL_datum *datum;
    6413             :     ExprEvalStep scratch;
    6414             : 
    6415             :     /* fetch back the hook data */
    6416       50144 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6417       50144 :     expr = (PLpgSQL_expr *) params->parserSetupArg;
    6418             : 
    6419             :     /* paramid's are 1-based, but dnos are 0-based */
    6420       50144 :     dno = param->paramid - 1;
    6421             :     Assert(dno >= 0 && dno < estate->ndatums);
    6422             : 
    6423             :     /* now we can access the target datum */
    6424       50144 :     datum = estate->datums[dno];
    6425             : 
    6426       50144 :     scratch.opcode = EEOP_PARAM_CALLBACK;
    6427       50144 :     scratch.resvalue = resv;
    6428       50144 :     scratch.resnull = resnull;
    6429             : 
    6430             :     /*
    6431             :      * Select appropriate eval function.  It seems worth special-casing
    6432             :      * DTYPE_VAR and DTYPE_RECFIELD for performance.  Also, we can determine
    6433             :      * in advance whether MakeExpandedObjectReadOnly() will be required.
    6434             :      * Currently, only VAR/PROMISE and REC datums could contain read/write
    6435             :      * expanded objects.
    6436             :      */
    6437       50144 :     if (datum->dtype == PLPGSQL_DTYPE_VAR)
    6438             :     {
    6439       53504 :         if (dno != expr->rwparam &&
    6440       26712 :             ((PLpgSQL_var *) datum)->datatype->typlen == -1)
    6441       12396 :             scratch.d.cparam.paramfunc = plpgsql_param_eval_var_ro;
    6442             :         else
    6443       14396 :             scratch.d.cparam.paramfunc = plpgsql_param_eval_var;
    6444             :     }
    6445       23352 :     else if (datum->dtype == PLPGSQL_DTYPE_RECFIELD)
    6446       14396 :         scratch.d.cparam.paramfunc = plpgsql_param_eval_recfield;
    6447        8956 :     else if (datum->dtype == PLPGSQL_DTYPE_PROMISE)
    6448             :     {
    6449       16448 :         if (dno != expr->rwparam &&
    6450        8224 :             ((PLpgSQL_var *) datum)->datatype->typlen == -1)
    6451        6868 :             scratch.d.cparam.paramfunc = plpgsql_param_eval_generic_ro;
    6452             :         else
    6453        1356 :             scratch.d.cparam.paramfunc = plpgsql_param_eval_generic;
    6454             :     }
    6455        1464 :     else if (datum->dtype == PLPGSQL_DTYPE_REC &&
    6456         732 :              dno != expr->rwparam)
    6457         732 :         scratch.d.cparam.paramfunc = plpgsql_param_eval_generic_ro;
    6458             :     else
    6459           0 :         scratch.d.cparam.paramfunc = plpgsql_param_eval_generic;
    6460             : 
    6461             :     /*
    6462             :      * Note: it's tempting to use paramarg to store the estate pointer and
    6463             :      * thereby save an indirection or two in the eval functions.  But that
    6464             :      * doesn't work because the compiled expression might be used with
    6465             :      * different estates for the same PL/pgSQL function.
    6466             :      */
    6467       50144 :     scratch.d.cparam.paramarg = NULL;
    6468       50144 :     scratch.d.cparam.paramid = param->paramid;
    6469       50144 :     scratch.d.cparam.paramtype = param->paramtype;
    6470       50144 :     ExprEvalPushStep(state, &scratch);
    6471       50144 : }
    6472             : 
    6473             : /*
    6474             :  * plpgsql_param_eval_var       evaluation of EEOP_PARAM_CALLBACK step
    6475             :  *
    6476             :  * This is specialized to the case of DTYPE_VAR variables for which
    6477             :  * we do not need to invoke MakeExpandedObjectReadOnly.
    6478             :  */
    6479             : static void
    6480      679794 : plpgsql_param_eval_var(ExprState *state, ExprEvalStep *op,
    6481             :                        ExprContext *econtext)
    6482             : {
    6483             :     ParamListInfo params;
    6484             :     PLpgSQL_execstate *estate;
    6485      679794 :     int         dno = op->d.cparam.paramid - 1;
    6486             :     PLpgSQL_var *var;
    6487             : 
    6488             :     /* fetch back the hook data */
    6489      679794 :     params = econtext->ecxt_param_list_info;
    6490      679794 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6491             :     Assert(dno >= 0 && dno < estate->ndatums);
    6492             : 
    6493             :     /* now we can access the target datum */
    6494      679794 :     var = (PLpgSQL_var *) estate->datums[dno];
    6495             :     Assert(var->dtype == PLPGSQL_DTYPE_VAR);
    6496             : 
    6497             :     /* inlined version of exec_eval_datum() */
    6498      679794 :     *op->resvalue = var->value;
    6499      679794 :     *op->resnull = var->isnull;
    6500             : 
    6501             :     /* safety check -- an assertion should be sufficient */
    6502             :     Assert(var->datatype->typoid == op->d.cparam.paramtype);
    6503      679794 : }
    6504             : 
    6505             : /*
    6506             :  * plpgsql_param_eval_var_ro        evaluation of EEOP_PARAM_CALLBACK step
    6507             :  *
    6508             :  * This is specialized to the case of DTYPE_VAR variables for which
    6509             :  * we need to invoke MakeExpandedObjectReadOnly.
    6510             :  */
    6511             : static void
    6512       41652 : plpgsql_param_eval_var_ro(ExprState *state, ExprEvalStep *op,
    6513             :                           ExprContext *econtext)
    6514             : {
    6515             :     ParamListInfo params;
    6516             :     PLpgSQL_execstate *estate;
    6517       41652 :     int         dno = op->d.cparam.paramid - 1;
    6518             :     PLpgSQL_var *var;
    6519             : 
    6520             :     /* fetch back the hook data */
    6521       41652 :     params = econtext->ecxt_param_list_info;
    6522       41652 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6523             :     Assert(dno >= 0 && dno < estate->ndatums);
    6524             : 
    6525             :     /* now we can access the target datum */
    6526       41652 :     var = (PLpgSQL_var *) estate->datums[dno];
    6527             :     Assert(var->dtype == PLPGSQL_DTYPE_VAR);
    6528             : 
    6529             :     /*
    6530             :      * Inlined version of exec_eval_datum() ... and while we're at it, force
    6531             :      * expanded datums to read-only.
    6532             :      */
    6533       41652 :     *op->resvalue = MakeExpandedObjectReadOnly(var->value,
    6534             :                                                var->isnull,
    6535             :                                                -1);
    6536       41652 :     *op->resnull = var->isnull;
    6537             : 
    6538             :     /* safety check -- an assertion should be sufficient */
    6539             :     Assert(var->datatype->typoid == op->d.cparam.paramtype);
    6540       41652 : }
    6541             : 
    6542             : /*
    6543             :  * plpgsql_param_eval_recfield      evaluation of EEOP_PARAM_CALLBACK step
    6544             :  *
    6545             :  * This is specialized to the case of DTYPE_RECFIELD variables, for which
    6546             :  * we never need to invoke MakeExpandedObjectReadOnly.
    6547             :  */
    6548             : static void
    6549       23868 : plpgsql_param_eval_recfield(ExprState *state, ExprEvalStep *op,
    6550             :                             ExprContext *econtext)
    6551             : {
    6552             :     ParamListInfo params;
    6553             :     PLpgSQL_execstate *estate;
    6554       23868 :     int         dno = op->d.cparam.paramid - 1;
    6555             :     PLpgSQL_recfield *recfield;
    6556             :     PLpgSQL_rec *rec;
    6557             :     ExpandedRecordHeader *erh;
    6558             : 
    6559             :     /* fetch back the hook data */
    6560       23868 :     params = econtext->ecxt_param_list_info;
    6561       23868 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6562             :     Assert(dno >= 0 && dno < estate->ndatums);
    6563             : 
    6564             :     /* now we can access the target datum */
    6565       23868 :     recfield = (PLpgSQL_recfield *) estate->datums[dno];
    6566             :     Assert(recfield->dtype == PLPGSQL_DTYPE_RECFIELD);
    6567             : 
    6568             :     /* inline the relevant part of exec_eval_datum */
    6569       23868 :     rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    6570       23868 :     erh = rec->erh;
    6571             : 
    6572             :     /*
    6573             :      * If record variable is NULL, instantiate it if it has a named composite
    6574             :      * type, else complain.  (This won't change the logical state of the
    6575             :      * record: it's still NULL.)
    6576             :      */
    6577       23868 :     if (erh == NULL)
    6578             :     {
    6579           2 :         instantiate_empty_record_variable(estate, rec);
    6580           2 :         erh = rec->erh;
    6581             :     }
    6582             : 
    6583             :     /*
    6584             :      * Look up the field's properties if we have not already, or if the tuple
    6585             :      * descriptor ID changed since last time.
    6586             :      */
    6587       23868 :     if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
    6588             :     {
    6589        3848 :         if (!expanded_record_lookup_field(erh,
    6590        1924 :                                           recfield->fieldname,
    6591             :                                           &recfield->finfo))
    6592           4 :             ereport(ERROR,
    6593             :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    6594             :                      errmsg("record \"%s\" has no field \"%s\"",
    6595             :                             rec->refname, recfield->fieldname)));
    6596        1920 :         recfield->rectupledescid = erh->er_tupdesc_id;
    6597             :     }
    6598             : 
    6599             :     /* OK to fetch the field value. */
    6600       23864 :     *op->resvalue = expanded_record_get_field(erh,
    6601             :                                               recfield->finfo.fnumber,
    6602             :                                               op->resnull);
    6603             : 
    6604             :     /* safety check -- needed for, eg, record fields */
    6605       23864 :     if (unlikely(recfield->finfo.ftypeid != op->d.cparam.paramtype))
    6606           4 :         ereport(ERROR,
    6607             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    6608             :                  errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
    6609             :                         op->d.cparam.paramid,
    6610             :                         format_type_be(recfield->finfo.ftypeid),
    6611             :                         format_type_be(op->d.cparam.paramtype))));
    6612       23860 : }
    6613             : 
    6614             : /*
    6615             :  * plpgsql_param_eval_generic       evaluation of EEOP_PARAM_CALLBACK step
    6616             :  *
    6617             :  * This handles all variable types, but assumes we do not need to invoke
    6618             :  * MakeExpandedObjectReadOnly.
    6619             :  */
    6620             : static void
    6621        1528 : plpgsql_param_eval_generic(ExprState *state, ExprEvalStep *op,
    6622             :                            ExprContext *econtext)
    6623             : {
    6624             :     ParamListInfo params;
    6625             :     PLpgSQL_execstate *estate;
    6626        1528 :     int         dno = op->d.cparam.paramid - 1;
    6627             :     PLpgSQL_datum *datum;
    6628             :     Oid         datumtype;
    6629             :     int32       datumtypmod;
    6630             : 
    6631             :     /* fetch back the hook data */
    6632        1528 :     params = econtext->ecxt_param_list_info;
    6633        1528 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6634             :     Assert(dno >= 0 && dno < estate->ndatums);
    6635             : 
    6636             :     /* now we can access the target datum */
    6637        1528 :     datum = estate->datums[dno];
    6638             : 
    6639             :     /* fetch datum's value */
    6640        1528 :     exec_eval_datum(estate, datum,
    6641             :                     &datumtype, &datumtypmod,
    6642             :                     op->resvalue, op->resnull);
    6643             : 
    6644             :     /* safety check -- needed for, eg, record fields */
    6645        1528 :     if (unlikely(datumtype != op->d.cparam.paramtype))
    6646           0 :         ereport(ERROR,
    6647             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    6648             :                  errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
    6649             :                         op->d.cparam.paramid,
    6650             :                         format_type_be(datumtype),
    6651             :                         format_type_be(op->d.cparam.paramtype))));
    6652        1528 : }
    6653             : 
    6654             : /*
    6655             :  * plpgsql_param_eval_generic_ro    evaluation of EEOP_PARAM_CALLBACK step
    6656             :  *
    6657             :  * This handles all variable types, but assumes we need to invoke
    6658             :  * MakeExpandedObjectReadOnly (hence, variable must be of a varlena type).
    6659             :  */
    6660             : static void
    6661        9556 : plpgsql_param_eval_generic_ro(ExprState *state, ExprEvalStep *op,
    6662             :                               ExprContext *econtext)
    6663             : {
    6664             :     ParamListInfo params;
    6665             :     PLpgSQL_execstate *estate;
    6666        9556 :     int         dno = op->d.cparam.paramid - 1;
    6667             :     PLpgSQL_datum *datum;
    6668             :     Oid         datumtype;
    6669             :     int32       datumtypmod;
    6670             : 
    6671             :     /* fetch back the hook data */
    6672        9556 :     params = econtext->ecxt_param_list_info;
    6673        9556 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6674             :     Assert(dno >= 0 && dno < estate->ndatums);
    6675             : 
    6676             :     /* now we can access the target datum */
    6677        9556 :     datum = estate->datums[dno];
    6678             : 
    6679             :     /* fetch datum's value */
    6680        9556 :     exec_eval_datum(estate, datum,
    6681             :                     &datumtype, &datumtypmod,
    6682             :                     op->resvalue, op->resnull);
    6683             : 
    6684             :     /* safety check -- needed for, eg, record fields */
    6685        9556 :     if (unlikely(datumtype != op->d.cparam.paramtype))
    6686           0 :         ereport(ERROR,
    6687             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    6688             :                  errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
    6689             :                         op->d.cparam.paramid,
    6690             :                         format_type_be(datumtype),
    6691             :                         format_type_be(op->d.cparam.paramtype))));
    6692             : 
    6693             :     /* force the value to read-only */
    6694        9556 :     *op->resvalue = MakeExpandedObjectReadOnly(*op->resvalue,
    6695             :                                                *op->resnull,
    6696             :                                                -1);
    6697        9556 : }
    6698             : 
    6699             : 
    6700             : /*
    6701             :  * exec_move_row            Move one tuple's values into a record or row
    6702             :  *
    6703             :  * tup and tupdesc may both be NULL if we're just assigning an indeterminate
    6704             :  * composite NULL to the target.  Alternatively, can have tup be NULL and
    6705             :  * tupdesc not NULL, in which case we assign a row of NULLs to the target.
    6706             :  *
    6707             :  * Since this uses the mcontext for workspace, caller should eventually call
    6708             :  * exec_eval_cleanup to prevent long-term memory leaks.
    6709             :  */
    6710             : static void
    6711       20548 : exec_move_row(PLpgSQL_execstate *estate,
    6712             :               PLpgSQL_variable *target,
    6713             :               HeapTuple tup, TupleDesc tupdesc)
    6714             : {
    6715       20548 :     ExpandedRecordHeader *newerh = NULL;
    6716             : 
    6717             :     /*
    6718             :      * If target is RECORD, we may be able to avoid field-by-field processing.
    6719             :      */
    6720       20548 :     if (target->dtype == PLPGSQL_DTYPE_REC)
    6721             :     {
    6722        5222 :         PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
    6723             : 
    6724             :         /*
    6725             :          * If we have no source tupdesc, just set the record variable to NULL.
    6726             :          * (If we have a source tupdesc but not a tuple, we'll set the
    6727             :          * variable to a row of nulls, instead.  This is odd perhaps, but
    6728             :          * backwards compatible.)
    6729             :          */
    6730        5222 :         if (tupdesc == NULL)
    6731             :         {
    6732        5528 :             if (rec->datatype &&
    6733        2764 :                 rec->datatype->typtype == TYPTYPE_DOMAIN)
    6734             :             {
    6735             :                 /*
    6736             :                  * If it's a composite domain, NULL might not be a legal
    6737             :                  * value, so we instead need to make an empty expanded record
    6738             :                  * and ensure that domain type checking gets done.  If there
    6739             :                  * is already an expanded record, piggyback on its lookups.
    6740             :                  */
    6741          36 :                 newerh = make_expanded_record_for_rec(estate, rec,
    6742             :                                                       NULL, rec->erh);
    6743          36 :                 expanded_record_set_tuple(newerh, NULL, false, false);
    6744          24 :                 assign_record_var(estate, rec, newerh);
    6745             :             }
    6746             :             else
    6747             :             {
    6748             :                 /* Just clear it to NULL */
    6749        2728 :                 if (rec->erh)
    6750           6 :                     DeleteExpandedObject(ExpandedRecordGetDatum(rec->erh));
    6751        2728 :                 rec->erh = NULL;
    6752             :             }
    6753        2752 :             return;
    6754             :         }
    6755             : 
    6756             :         /*
    6757             :          * Build a new expanded record with appropriate tupdesc.
    6758             :          */
    6759        2458 :         newerh = make_expanded_record_for_rec(estate, rec, tupdesc, NULL);
    6760             : 
    6761             :         /*
    6762             :          * If the rowtypes match, or if we have no tuple anyway, we can
    6763             :          * complete the assignment without field-by-field processing.
    6764             :          *
    6765             :          * The tests here are ordered more or less in order of cheapness.  We
    6766             :          * can easily detect it will work if the target is declared RECORD or
    6767             :          * has the same typeid as the source.  But when assigning from a query
    6768             :          * result, it's common to have a source tupdesc that's labeled RECORD
    6769             :          * but is actually physically compatible with a named-composite-type
    6770             :          * target, so it's worth spending extra cycles to check for that.
    6771             :          */
    6772        2628 :         if (rec->rectypeid == RECORDOID ||
    6773         340 :             rec->rectypeid == tupdesc->tdtypeid ||
    6774         170 :             !HeapTupleIsValid(tup) ||
    6775         170 :             compatible_tupdescs(tupdesc, expanded_record_get_tupdesc(newerh)))
    6776             :         {
    6777        2382 :             if (!HeapTupleIsValid(tup))
    6778             :             {
    6779             :                 /* No data, so force the record into all-nulls state */
    6780          52 :                 deconstruct_expanded_record(newerh);
    6781             :             }
    6782             :             else
    6783             :             {
    6784             :                 /* No coercion is needed, so just assign the row value */
    6785        2330 :                 expanded_record_set_tuple(newerh, tup, true, !estate->atomic);
    6786             :             }
    6787             : 
    6788             :             /* Complete the assignment */
    6789        2376 :             assign_record_var(estate, rec, newerh);
    6790             : 
    6791        2376 :             return;
    6792             :         }
    6793             :     }
    6794             : 
    6795             :     /*
    6796             :      * Otherwise, deconstruct the tuple and do field-by-field assignment,
    6797             :      * using exec_move_row_from_fields.
    6798             :      */
    6799       15402 :     if (tupdesc && HeapTupleIsValid(tup))
    6800       15250 :     {
    6801       15276 :         int         td_natts = tupdesc->natts;
    6802             :         Datum      *values;
    6803             :         bool       *nulls;
    6804             :         Datum       values_local[64];
    6805             :         bool        nulls_local[64];
    6806             : 
    6807             :         /*
    6808             :          * Need workspace arrays.  If td_natts is small enough, use local
    6809             :          * arrays to save doing a palloc.  Even if it's not small, we can
    6810             :          * allocate both the Datum and isnull arrays in one palloc chunk.
    6811             :          */
    6812       15276 :         if (td_natts <= lengthof(values_local))
    6813             :         {
    6814       15276 :             values = values_local;
    6815       15276 :             nulls = nulls_local;
    6816             :         }
    6817             :         else
    6818             :         {
    6819             :             char       *chunk;
    6820             : 
    6821           0 :             chunk = eval_mcontext_alloc(estate,
    6822             :                                         td_natts * (sizeof(Datum) + sizeof(bool)));
    6823           0 :             values = (Datum *) chunk;
    6824           0 :             nulls = (bool *) (chunk + td_natts * sizeof(Datum));
    6825             :         }
    6826             : 
    6827       15276 :         heap_deform_tuple(tup, tupdesc, values, nulls);
    6828             : 
    6829       15276 :         exec_move_row_from_fields(estate, target, newerh,
    6830             :                                   values, nulls, tupdesc);
    6831             :     }
    6832             :     else
    6833             :     {
    6834             :         /*
    6835             :          * Assign all-nulls.
    6836             :          */
    6837         126 :         exec_move_row_from_fields(estate, target, newerh,
    6838             :                                   NULL, NULL, NULL);
    6839             :     }
    6840             : }
    6841             : 
    6842             : /*
    6843             :  * Verify that a PLpgSQL_rec's rectypeid is up-to-date.
    6844             :  */
    6845             : static void
    6846         334 : revalidate_rectypeid(PLpgSQL_rec *rec)
    6847             : {
    6848         334 :     PLpgSQL_type *typ = rec->datatype;
    6849             :     TypeCacheEntry *typentry;
    6850             : 
    6851         334 :     if (rec->rectypeid == RECORDOID)
    6852           6 :         return;                 /* it's RECORD, so nothing to do */
    6853             :     Assert(typ != NULL);
    6854         656 :     if (typ->tcache &&
    6855         328 :         typ->tcache->tupDesc_identifier == typ->tupdesc_id)
    6856         316 :         return;                 /* known up-to-date */
    6857             : 
    6858             :     /*
    6859             :      * typcache entry has suffered invalidation, so re-look-up the type name
    6860             :      * if possible, and then recheck the type OID.  If we don't have a
    6861             :      * TypeName, then we just have to soldier on with the OID we've got.
    6862             :      */
    6863          12 :     if (typ->origtypname != NULL)
    6864             :     {
    6865             :         /* this bit should match parse_datatype() in pl_gram.y */
    6866           8 :         typenameTypeIdAndMod(NULL, typ->origtypname,
    6867             :                              &typ->typoid,
    6868             :                              &typ->atttypmod);
    6869             :     }
    6870             : 
    6871             :     /* this bit should match build_datatype() in pl_comp.c */
    6872          10 :     typentry = lookup_type_cache(typ->typoid,
    6873             :                                  TYPECACHE_TUPDESC |
    6874             :                                  TYPECACHE_DOMAIN_BASE_INFO);
    6875          10 :     if (typentry->typtype == TYPTYPE_DOMAIN)
    6876           0 :         typentry = lookup_type_cache(typentry->domainBaseType,
    6877             :                                      TYPECACHE_TUPDESC);
    6878          10 :     if (typentry->tupDesc == NULL)
    6879             :     {
    6880             :         /*
    6881             :          * If we get here, user tried to replace a composite type with a
    6882             :          * non-composite one.  We're not gonna support that.
    6883             :          */
    6884           0 :         ereport(ERROR,
    6885             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    6886             :                  errmsg("type %s is not composite",
    6887             :                         format_type_be(typ->typoid))));
    6888             :     }
    6889             : 
    6890             :     /*
    6891             :      * Update tcache and tupdesc_id.  Since we don't support changing to a
    6892             :      * non-composite type, none of the rest of *typ needs to change.
    6893             :      */
    6894          10 :     typ->tcache = typentry;
    6895          10 :     typ->tupdesc_id = typentry->tupDesc_identifier;
    6896             : 
    6897             :     /*
    6898             :      * Update *rec, too.  (We'll deal with subsidiary RECFIELDs as needed.)
    6899             :      */
    6900          10 :     rec->rectypeid = typ->typoid;
    6901             : }
    6902             : 
    6903             : /*
    6904             :  * Build an expanded record object suitable for assignment to "rec".
    6905             :  *
    6906             :  * Caller must supply either a source tuple descriptor or a source expanded
    6907             :  * record (not both).  If the record variable has declared type RECORD,
    6908             :  * it'll adopt the source's rowtype.  Even if it doesn't, we may be able to
    6909             :  * piggyback on a source expanded record to save a typcache lookup.
    6910             :  *
    6911             :  * Caller must fill the object with data, then do assign_record_var().
    6912             :  *
    6913             :  * The new record is initially put into the mcontext, so it will be cleaned up
    6914             :  * if we fail before reaching assign_record_var().
    6915             :  */
    6916             : static ExpandedRecordHeader *
    6917        2522 : make_expanded_record_for_rec(PLpgSQL_execstate *estate,
    6918             :                              PLpgSQL_rec *rec,
    6919             :                              TupleDesc srctupdesc,
    6920             :                              ExpandedRecordHeader *srcerh)
    6921             : {
    6922             :     ExpandedRecordHeader *newerh;
    6923        2522 :     MemoryContext mcontext = get_eval_mcontext(estate);
    6924             : 
    6925        2522 :     if (rec->rectypeid != RECORDOID)
    6926             :     {
    6927             :         /*
    6928             :          * Make sure rec->rectypeid is up-to-date before using it.
    6929             :          */
    6930         230 :         revalidate_rectypeid(rec);
    6931             : 
    6932             :         /*
    6933             :          * New record must be of desired type, but maybe srcerh has already
    6934             :          * done all the same lookups.
    6935             :          */
    6936         230 :         if (srcerh && rec->rectypeid == srcerh->er_decltypeid)
    6937          30 :             newerh = make_expanded_record_from_exprecord(srcerh,
    6938             :                                                          mcontext);
    6939             :         else
    6940         200 :             newerh = make_expanded_record_from_typeid(rec->rectypeid, -1,
    6941             :                                                       mcontext);
    6942             :     }
    6943             :     else
    6944             :     {
    6945             :         /*
    6946             :          * We'll adopt the input tupdesc.  We can still use
    6947             :          * make_expanded_record_from_exprecord, if srcerh isn't a composite
    6948             :          * domain.  (If it is, we effectively adopt its base type.)
    6949             :          */
    6950        2292 :         if (srcerh && !ExpandedRecordIsDomain(srcerh))
    6951           4 :             newerh = make_expanded_record_from_exprecord(srcerh,
    6952             :                                                          mcontext);
    6953             :         else
    6954             :         {
    6955        2288 :             if (!srctupdesc)
    6956           0 :                 srctupdesc = expanded_record_get_tupdesc(srcerh);
    6957        2288 :             newerh = make_expanded_record_from_tupdesc(srctupdesc,
    6958             :                                                        mcontext);
    6959             :         }
    6960             :     }
    6961             : 
    6962        2522 :     return newerh;
    6963             : }
    6964             : 
    6965             : /*
    6966             :  * exec_move_row_from_fields    Move arrays of field values into a record or row
    6967             :  *
    6968             :  * When assigning to a record, the caller must have already created a suitable
    6969             :  * new expanded record object, newerh.  Pass NULL when assigning to a row.
    6970             :  *
    6971             :  * tupdesc describes the input row, which might have different column
    6972             :  * types and/or different dropped-column positions than the target.
    6973             :  * values/nulls/tupdesc can all be NULL if we just want to assign nulls to
    6974             :  * all fields of the record or row.
    6975             :  *
    6976             :  * Since this uses the mcontext for workspace, caller should eventually call
    6977             :  * exec_eval_cleanup to prevent long-term memory leaks.
    6978             :  */
    6979             : static void
    6980       15422 : exec_move_row_from_fields(PLpgSQL_execstate *estate,
    6981             :                           PLpgSQL_variable *target,
    6982             :                           ExpandedRecordHeader *newerh,
    6983             :                           Datum *values, bool *nulls,
    6984             :                           TupleDesc tupdesc)
    6985             : {
    6986       15422 :     int         td_natts = tupdesc ? tupdesc->natts : 0;
    6987             :     int         fnum;
    6988             :     int         anum;
    6989       15422 :     int         strict_multiassignment_level = 0;
    6990             : 
    6991             :     /*
    6992             :      * The extra check strict strict_multi_assignment can be active, only when
    6993             :      * input tupdesc is specified.
    6994             :      */
    6995       15422 :     if (tupdesc != NULL)
    6996             :     {
    6997       15296 :         if (plpgsql_extra_errors & PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT)
    6998          24 :             strict_multiassignment_level = ERROR;
    6999       15272 :         else if (plpgsql_extra_warnings & PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT)
    7000          12 :             strict_multiassignment_level = WARNING;
    7001             :     }
    7002             : 
    7003             :     /* Handle RECORD-target case */
    7004       15422 :     if (target->dtype == PLPGSQL_DTYPE_REC)
    7005             :     {
    7006          96 :         PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
    7007             :         TupleDesc   var_tupdesc;
    7008             :         Datum       newvalues_local[64];
    7009             :         bool        newnulls_local[64];
    7010             : 
    7011             :         Assert(newerh != NULL); /* caller must have built new object */
    7012             : 
    7013          96 :         var_tupdesc = expanded_record_get_tupdesc(newerh);
    7014             : 
    7015             :         /*
    7016             :          * Coerce field values if needed.  This might involve dealing with
    7017             :          * different sets of dropped columns and/or coercing individual column
    7018             :          * types.  That's sort of a pain, but historically plpgsql has allowed
    7019             :          * it, so we preserve the behavior.  However, it's worth a quick check
    7020             :          * to see if the tupdescs are identical.  (Since expandedrecord.c
    7021             :          * prefers to use refcounted tupdescs from the typcache, expanded
    7022             :          * records with the same rowtype will have pointer-equal tupdescs.)
    7023             :          */
    7024          96 :         if (var_tupdesc != tupdesc)
    7025             :         {
    7026          82 :             int         vtd_natts = var_tupdesc->natts;
    7027             :             Datum      *newvalues;
    7028             :             bool       *newnulls;
    7029             : 
    7030             :             /*
    7031             :              * Need workspace arrays.  If vtd_natts is small enough, use local
    7032             :              * arrays to save doing a palloc.  Even if it's not small, we can
    7033             :              * allocate both the Datum and isnull arrays in one palloc chunk.
    7034             :              */
    7035          82 :             if (vtd_natts <= lengthof(newvalues_local))
    7036             :             {
    7037          82 :                 newvalues = newvalues_local;
    7038          82 :                 newnulls = newnulls_local;
    7039             :             }
    7040             :             else
    7041             :             {
    7042             :                 char       *chunk;
    7043             : 
    7044           0 :                 chunk = eval_mcontext_alloc(estate,
    7045             :                                             vtd_natts * (sizeof(Datum) + sizeof(bool)));
    7046           0 :                 newvalues = (Datum *) chunk;
    7047           0 :                 newnulls = (bool *) (chunk + vtd_natts * sizeof(Datum));
    7048             :             }
    7049             : 
    7050             :             /* Walk over destination columns */
    7051          82 :             anum = 0;
    7052         254 :             for (fnum = 0; fnum < vtd_natts; fnum++)
    7053             :             {
    7054         178 :                 Form_pg_attribute attr = TupleDescAttr(var_tupdesc, fnum);
    7055             :                 Datum       value;
    7056             :                 bool        isnull;
    7057             :                 Oid         valtype;
    7058             :                 int32       valtypmod;
    7059             : 
    7060         178 :                 if (attr->attisdropped)
    7061             :                 {
    7062             :                     /* expanded_record_set_fields should ignore this column */
    7063          14 :                     continue;   /* skip dropped column in record */
    7064             :                 }
    7065             : 
    7066         488 :                 while (anum < td_natts &&
    7067         160 :                        TupleDescAttr(tupdesc, anum)->attisdropped)
    7068           0 :                     anum++;     /* skip dropped column in tuple */
    7069             : 
    7070         164 :                 if (anum < td_natts)
    7071             :                 {
    7072         160 :                     value = values[anum];
    7073         160 :                     isnull = nulls[anum];
    7074         160 :                     valtype = TupleDescAttr(tupdesc, anum)->atttypid;
    7075         160 :                     valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
    7076         160 :                     anum++;
    7077             :                 }
    7078             :                 else
    7079             :                 {
    7080             :                     /* no source for destination column */
    7081           4 :                     value = (Datum) 0;
    7082           4 :                     isnull = true;
    7083           4 :                     valtype = UNKNOWNOID;
    7084           4 :                     valtypmod = -1;
    7085             : 
    7086             :                     /* When source value is missing */
    7087           4 :                     if (strict_multiassignment_level)
    7088           4 :                         ereport(strict_multiassignment_level,
    7089             :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    7090             :                                  errmsg("number of source and target fields in assignment does not match"),
    7091             :                         /* translator: %s represents a name of an extra check */
    7092             :                                  errdetail("%s check of %s is active.",
    7093             :                                            "strict_multi_assignment",
    7094             :                                            strict_multiassignment_level == ERROR ? "extra_errors" :
    7095             :                                            "extra_warnings"),
    7096             :                                  errhint("Make sure the query returns the exact list of columns.")));
    7097             :                 }
    7098             : 
    7099             :                 /* Cast the new value to the right type, if needed. */
    7100         160 :                 newvalues[fnum] = exec_cast_value(estate,
    7101             :                                                   value,
    7102             :                                                   &isnull,
    7103             :                                                   valtype,
    7104             :                                                   valtypmod,
    7105             :                                                   attr->atttypid,
    7106             :                                                   attr->atttypmod);
    7107         158 :                 newnulls[fnum] = isnull;
    7108             :             }
    7109             : 
    7110             :             /*
    7111             :              * When strict_multiassignment extra check is active, then ensure
    7112             :              * there are no unassigned source attributes.
    7113             :              */
    7114          76 :             if (strict_multiassignment_level && anum < td_natts)
    7115             :             {
    7116             :                 /* skip dropped columns in the source descriptor */
    7117          12 :                 while (anum < td_natts &&
    7118           4 :                        TupleDescAttr(tupdesc, anum)->attisdropped)
    7119           0 :                     anum++;
    7120             : 
    7121           4 :                 if (anum < td_natts)
    7122           4 :                     ereport(strict_multiassignment_level,
    7123             :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
    7124             :                              errmsg("number of source and target fields in assignment does not match"),
    7125             :                     /* translator: %s represents a name of an extra check */
    7126             :                              errdetail("%s check of %s is active.",
    7127             :                                        "strict_multi_assignment",
    7128             :                                        strict_multiassignment_level == ERROR ? "extra_errors" :
    7129             :                                        "extra_warnings"),
    7130             :                              errhint("Make sure the query returns the exact list of columns.")));
    7131             :             }
    7132             : 
    7133          72 :             values = newvalues;
    7134          72 :             nulls = newnulls;
    7135             :         }
    7136             : 
    7137             :         /* Insert the coerced field values into the new expanded record */
    7138          86 :         expanded_record_set_fields(newerh, values, nulls, !estate->atomic);
    7139             : 
    7140             :         /* Complete the assignment */
    7141          78 :         assign_record_var(estate, rec, newerh);
    7142             : 
    7143          78 :         return;
    7144             :     }
    7145             : 
    7146             :     /* newerh should not have been passed in non-RECORD cases */
    7147             :     Assert(newerh == NULL);
    7148             : 
    7149             :     /*
    7150             :      * For a row, we assign the individual field values to the variables the
    7151             :      * row points to.
    7152             :      *
    7153             :      * NOTE: both this code and the record code above silently ignore extra
    7154             :      * columns in the source and assume NULL for missing columns.  This is
    7155             :      * pretty dubious but it's the historical behavior.
    7156             :      *
    7157             :      * If we have no input data at all, we'll assign NULL to all columns of
    7158             :      * the row variable.
    7159             :      */
    7160       15326 :     if (target->dtype == PLPGSQL_DTYPE_ROW)
    7161             :     {
    7162       15326 :         PLpgSQL_row *row = (PLpgSQL_row *) target;
    7163             : 
    7164       15326 :         anum = 0;
    7165       31178 :         for (fnum = 0; fnum < row->nfields; fnum++)
    7166             :         {
    7167             :             PLpgSQL_var *var;
    7168             :             Datum       value;
    7169             :             bool        isnull;
    7170             :             Oid         valtype;
    7171             :             int32       valtypmod;
    7172             : 
    7173       15856 :             var = (PLpgSQL_var *) (estate->datums[row->varnos[fnum]]);
    7174             : 
    7175       47430 :             while (anum < td_natts &&
    7176       15718 :                    TupleDescAttr(tupdesc, anum)->attisdropped)
    7177           0 :                 anum++;         /* skip dropped column in tuple */
    7178             : 
    7179       15856 :             if (anum < td_natts)
    7180             :             {
    7181       15718 :                 value = values[anum];
    7182       15718 :                 isnull = nulls[anum];
    7183       15718 :                 valtype = TupleDescAttr(tupdesc, anum)->atttypid;
    7184       15718 :                 valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
    7185       15718 :                 anum++;
    7186             :             }
    7187             :             else
    7188             :             {
    7189             :                 /* no source for destination column */
    7190         138 :                 value = (Datum) 0;
    7191         138 :                 isnull = true;
    7192         138 :                 valtype = UNKNOWNOID;
    7193         138 :                 valtypmod = -1;
    7194             : 
    7195         138 :                 if (strict_multiassignment_level)
    7196           8 :                     ereport(strict_multiassignment_level,
    7197             :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
    7198             :                              errmsg("number of source and target fields in assignment does not match"),
    7199             :                     /* translator: %s represents a name of an extra check */
    7200             :                              errdetail("%s check of %s is active.",
    7201             :                                        "strict_multi_assignment",
    7202             :                                        strict_multiassignment_level == ERROR ? "extra_errors" :
    7203             :                                        "extra_warnings"),
    7204             :                              errhint("Make sure the query returns the exact list of columns.")));
    7205             :             }
    7206             : 
    7207       15852 :             exec_assign_value(estate, (PLpgSQL_datum *) var,
    7208             :                               value, isnull, valtype, valtypmod);
    7209             :         }
    7210             : 
    7211             :         /*
    7212             :          * When strict_multiassignment extra check is active, ensure there are
    7213             :          * no unassigned source attributes.
    7214             :          */
    7215       15322 :         if (strict_multiassignment_level && anum < td_natts)
    7216             :         {
    7217          24 :             while (anum < td_natts &&
    7218           8 :                    TupleDescAttr(tupdesc, anum)->attisdropped)
    7219           0 :                 anum++;         /* skip dropped column in tuple */
    7220             : 
    7221           8 :             if (anum < td_natts)
    7222           8 :                 ereport(strict_multiassignment_level,
    7223             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    7224             :                          errmsg("number of source and target fields in assignment does not match"),
    7225             :                 /* translator: %s represents a name of an extra check */
    7226             :                          errdetail("%s check of %s is active.",
    7227             :                                    "strict_multi_assignment",
    7228             :                                    strict_multiassignment_level == ERROR ? "extra_errors" :
    7229             :                                    "extra_warnings"),
    7230             :                          errhint("Make sure the query returns the exact list of columns.")));
    7231             :         }
    7232             : 
    7233       15318 :         return;
    7234             :     }
    7235             : 
    7236           0 :     elog(ERROR, "unsupported target type: %d", target->dtype);
    7237             : }
    7238             : 
    7239             : /*
    7240             :  * compatible_tupdescs: detect whether two tupdescs are physically compatible
    7241             :  *
    7242             :  * TRUE indicates that a tuple satisfying src_tupdesc can be used directly as
    7243             :  * a value for a composite variable using dst_tupdesc.
    7244             :  */
    7245             : static bool
    7246         186 : compatible_tupdescs(TupleDesc src_tupdesc, TupleDesc dst_tupdesc)
    7247             : {
    7248             :     int         i;
    7249             : 
    7250             :     /* Possibly we could allow src_tupdesc to have extra columns? */
    7251         186 :     if (dst_tupdesc->natts != src_tupdesc->natts)
    7252          18 :         return false;
    7253             : 
    7254         422 :     for (i = 0; i < dst_tupdesc->natts; i++)
    7255             :     {
    7256         318 :         Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
    7257         318 :         Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
    7258             : 
    7259         318 :         if (dattr->attisdropped != sattr->attisdropped)
    7260           4 :             return false;
    7261         314 :         if (!dattr->attisdropped)
    7262             :         {
    7263             :             /* Normal columns must match by type and typmod */
    7264         568 :             if (dattr->atttypid != sattr->atttypid ||
    7265         262 :                 (dattr->atttypmod >= 0 &&
    7266           8 :                  dattr->atttypmod != sattr->atttypmod))
    7267          60 :                 return false;
    7268             :         }
    7269             :         else
    7270             :         {
    7271             :             /* Dropped columns are OK as long as length/alignment match */
    7272           0 :             if (dattr->attlen != sattr->attlen ||
    7273           0 :                 dattr->attalign != sattr->attalign)
    7274           0 :                 return false;
    7275             :         }
    7276             :     }
    7277         104 :     return true;
    7278             : }
    7279             : 
    7280             : /* ----------
    7281             :  * make_tuple_from_row      Make a tuple from the values of a row object
    7282             :  *
    7283             :  * A NULL return indicates rowtype mismatch; caller must raise suitable error
    7284             :  *
    7285             :  * The result tuple is freshly palloc'd in caller's context.  Some junk
    7286             :  * may be left behind in eval_mcontext, too.
    7287             :  * ----------
    7288             :  */
    7289             : static HeapTuple
    7290         176 : make_tuple_from_row(PLpgSQL_execstate *estate,
    7291             :                     PLpgSQL_row *row,
    7292             :                     TupleDesc tupdesc)
    7293             : {
    7294         176 :     int         natts = tupdesc->natts;
    7295             :     HeapTuple   tuple;
    7296             :     Datum      *dvalues;
    7297             :     bool       *nulls;
    7298             :     int         i;
    7299             : 
    7300         176 :     if (natts != row->nfields)
    7301           0 :         return NULL;
    7302             : 
    7303         176 :     dvalues = (Datum *) eval_mcontext_alloc0(estate, natts * sizeof(Datum));
    7304         176 :     nulls = (bool *) eval_mcontext_alloc(estate, natts * sizeof(bool));
    7305             : 
    7306         526 :     for (i = 0; i < natts; i++)
    7307             :     {
    7308             :         Oid         fieldtypeid;
    7309             :         int32       fieldtypmod;
    7310             : 
    7311         350 :         if (TupleDescAttr(tupdesc, i)->attisdropped)
    7312             :         {
    7313           0 :             nulls[i] = true;    /* leave the column as null */
    7314           0 :             continue;
    7315             :         }
    7316             : 
    7317         700 :         exec_eval_datum(estate, estate->datums[row->varnos[i]],
    7318             :                         &fieldtypeid, &fieldtypmod,
    7319         350 :                         &dvalues[i], &nulls[i]);
    7320         350 :         if (fieldtypeid != TupleDescAttr(tupdesc, i)->atttypid)
    7321           0 :             return NULL;
    7322             :         /* XXX should we insist on typmod match, too? */
    7323             :     }
    7324             : 
    7325         176 :     tuple = heap_form_tuple(tupdesc, dvalues, nulls);
    7326             : 
    7327         176 :     return tuple;
    7328             : }
    7329             : 
    7330             : /*
    7331             :  * deconstruct_composite_datum      extract tuple+tupdesc from composite Datum
    7332             :  *
    7333             :  * The caller must supply a HeapTupleData variable, in which we set up a
    7334             :  * tuple header pointing to the composite datum's body.  To make the tuple
    7335             :  * value outlive that variable, caller would need to apply heap_copytuple...
    7336             :  * but current callers only need a short-lived tuple value anyway.
    7337             :  *
    7338             :  * Returns a pointer to the TupleDesc of the datum's rowtype.
    7339             :  * Caller is responsible for calling ReleaseTupleDesc when done with it.
    7340             :  *
    7341             :  * Note: it's caller's responsibility to be sure value is of composite type.
    7342             :  * Also, best to call this in a short-lived context, as it might leak memory.
    7343             :  */
    7344             : static TupleDesc
    7345         440 : deconstruct_composite_datum(Datum value, HeapTupleData *tmptup)
    7346             : {
    7347             :     HeapTupleHeader td;
    7348             :     Oid         tupType;
    7349             :     int32       tupTypmod;
    7350             : 
    7351             :     /* Get tuple body (note this could involve detoasting) */
    7352         440 :     td = DatumGetHeapTupleHeader(value);
    7353             : 
    7354             :     /* Build a temporary HeapTuple control structure */
    7355         440 :     tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
    7356         440 :     ItemPointerSetInvalid(&(tmptup->t_self));
    7357         440 :     tmptup->t_tableOid = InvalidOid;
    7358         440 :     tmptup->t_data = td;
    7359             : 
    7360             :     /* Extract rowtype info and find a tupdesc */
    7361         440 :     tupType = HeapTupleHeaderGetTypeId(td);
    7362         440 :     tupTypmod = HeapTupleHeaderGetTypMod(td);
    7363         440 :     return lookup_rowtype_tupdesc(tupType, tupTypmod);
    7364             : }
    7365             : 
    7366             : /*
    7367             :  * exec_move_row_from_datum     Move a composite Datum into a record or row
    7368             :  *
    7369             :  * This is equivalent to deconstruct_composite_datum() followed by
    7370             :  * exec_move_row(), but we can optimize things if the Datum is an
    7371             :  * expanded-record reference.
    7372             :  *
    7373             :  * Note: it's caller's responsibility to be sure value is of composite type.
    7374             :  */
    7375             : static void
    7376         448 : exec_move_row_from_datum(PLpgSQL_execstate *estate,
    7377             :                          PLpgSQL_variable *target,
    7378             :                          Datum value)
    7379             : {
    7380             :     /* Check to see if source is an expanded record */
    7381         448 :     if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(value)))
    7382          20 :     {
    7383          38 :         ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(value);
    7384          38 :         ExpandedRecordHeader *newerh = NULL;
    7385             : 
    7386             :         Assert(erh->er_magic == ER_MAGIC);
    7387             : 
    7388             :         /* These cases apply if the target is record not row... */
    7389          38 :         if (target->dtype == PLPGSQL_DTYPE_REC)
    7390             :         {
    7391          38 :             PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
    7392             : 
    7393             :             /*
    7394             :              * If it's the same record already stored in the variable, do
    7395             :              * nothing.  This would happen only in silly cases like "r := r",
    7396             :              * but we need some check to avoid possibly freeing the variable's
    7397             :              * live value below.  Note that this applies even if what we have
    7398             :              * is a R/O pointer.
    7399             :              */
    7400          38 :             if (erh == rec->erh)
    7401           2 :                 return;
    7402             : 
    7403             :             /*
    7404             :              * Make sure rec->rectypeid is up-to-date before using it.
    7405             :              */
    7406          36 :             revalidate_rectypeid(rec);
    7407             : 
    7408             :             /*
    7409             :              * If we have a R/W pointer, we're allowed to just commandeer
    7410             :              * ownership of the expanded record.  If it's of the right type to
    7411             :              * put into the record variable, do that.  (Note we don't accept
    7412             :              * an expanded record of a composite-domain type as a RECORD
    7413             :              * value.  We'll treat it as the base composite type instead;
    7414             :              * compare logic in make_expanded_record_for_rec.)
    7415             :              */
    7416          42 :             if (VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(value)) &&
    7417           8 :                 (rec->rectypeid == erh->er_decltypeid ||
    7418           4 :                  (rec->rectypeid == RECORDOID &&
    7419           2 :                   !ExpandedRecordIsDomain(erh))))
    7420             :             {
    7421           6 :                 assign_record_var(estate, rec, erh);
    7422           6 :                 return;
    7423             :             }
    7424             : 
    7425             :             /*
    7426             :              * If we already have an expanded record object in the target
    7427             :              * variable, and the source record contains a valid tuple
    7428             :              * representation with the right rowtype, then we can skip making
    7429             :              * a new expanded record and just assign the tuple with
    7430             :              * expanded_record_set_tuple.  (We can't do the equivalent if we
    7431             :              * have to do field-by-field assignment, since that wouldn't be
    7432             :              * atomic if there's an error.)  We consider that there's a
    7433             :              * rowtype match only if it's the same named composite type or
    7434             :              * same registered rowtype; checking for matches of anonymous
    7435             :              * rowtypes would be more expensive than this is worth.
    7436             :              */
    7437          38 :             if (rec->erh &&
    7438          12 :                 (erh->flags & ER_FLAG_FVALUE_VALID) &&
    7439           6 :                 erh->er_typeid == rec->erh->er_typeid &&
    7440           2 :                 (erh->er_typeid != RECORDOID ||
    7441           0 :                  (erh->er_typmod == rec->erh->er_typmod &&
    7442           0 :                   erh->er_typmod >= 0)))
    7443             :             {
    7444           2 :                 expanded_record_set_tuple(rec->erh, erh->fvalue,
    7445           2 :                                           true, !estate->atomic);
    7446           2 :                 return;
    7447             :             }
    7448             : 
    7449             :             /*
    7450             :              * Otherwise we're gonna need a new expanded record object.  Make
    7451             :              * it here in hopes of piggybacking on the source object's
    7452             :              * previous typcache lookup.
    7453             :              */
    7454          28 :             newerh = make_expanded_record_for_rec(estate, rec, NULL, erh);
    7455             : 
    7456             :             /*
    7457             :              * If the expanded record contains a valid tuple representation,
    7458             :              * and we don't need rowtype conversion, then just copying the
    7459             :              * tuple is probably faster than field-by-field processing.  (This
    7460             :              * isn't duplicative of the previous check, since here we will
    7461             :              * catch the case where the record variable was previously empty.)
    7462             :              */
    7463          38 :             if ((erh->flags & ER_FLAG_FVALUE_VALID) &&
    7464          18 :                 (rec->rectypeid == RECORDOID ||
    7465           8 :                  rec->rectypeid == erh->er_typeid))
    7466             :             {
    7467           8 :                 expanded_record_set_tuple(newerh, erh->fvalue,
    7468           8 :                                           true, !estate->atomic);
    7469           8 :                 assign_record_var(estate, rec, newerh);
    7470           8 :                 return;
    7471             :             }
    7472             : 
    7473             :             /*
    7474             :              * Need to special-case empty source record, else code below would
    7475             :              * leak newerh.
    7476             :              */
    7477          20 :             if (ExpandedRecordIsEmpty(erh))
    7478             :             {
    7479             :                 /* Set newerh to a row of NULLs */
    7480           0 :                 deconstruct_expanded_record(newerh);
    7481           0 :                 assign_record_var(estate, rec, newerh);
    7482           0 :                 return;
    7483             :             }
    7484             :         }                       /* end of record-target-only cases */
    7485             : 
    7486             :         /*
    7487             :          * If the source expanded record is empty, we should treat that like a
    7488             :          * NULL tuple value.  (We're unlikely to see such a case, but we must
    7489             :          * check this; deconstruct_expanded_record would cause a change of
    7490             :          * logical state, which is not OK.)
    7491             :          */
    7492          20 :         if (ExpandedRecordIsEmpty(erh))
    7493             :         {
    7494           0 :             exec_move_row(estate, target, NULL,
    7495             :                           expanded_record_get_tupdesc(erh));
    7496           0 :             return;
    7497             :         }
    7498             : 
    7499             :         /*
    7500             :          * Otherwise, ensure that the source record is deconstructed, and
    7501             :          * assign from its field values.
    7502             :          */
    7503          20 :         deconstruct_expanded_record(erh);
    7504          20 :         exec_move_row_from_fields(estate, target, newerh,
    7505             :                                   erh->dvalues, erh->dnulls,
    7506             :                                   expanded_record_get_tupdesc(erh));
    7507             :     }
    7508             :     else
    7509             :     {
    7510             :         /*
    7511             :          * Nope, we've got a plain composite Datum.  Deconstruct it; but we
    7512             :          * don't use deconstruct_composite_datum(), because we may be able to
    7513             :          * skip calling lookup_rowtype_tupdesc().
    7514             :          */
    7515             :         HeapTupleHeader td;
    7516             :         HeapTupleData tmptup;
    7517             :         Oid         tupType;
    7518             :         int32       tupTypmod;
    7519             :         TupleDesc   tupdesc;
    7520             :         MemoryContext oldcontext;
    7521             : 
    7522             :         /* Ensure that any detoasted data winds up in the eval_mcontext */
    7523         410 :         oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    7524             :         /* Get tuple body (note this could involve detoasting) */
    7525         410 :         td = DatumGetHeapTupleHeader(value);
    7526         410 :         MemoryContextSwitchTo(oldcontext);
    7527             : 
    7528             :         /* Build a temporary HeapTuple control structure */
    7529         410 :         tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
    7530         410 :         ItemPointerSetInvalid(&(tmptup.t_self));
    7531         410 :         tmptup.t_tableOid = InvalidOid;
    7532         410 :         tmptup.t_data = td;
    7533             : 
    7534             :         /* Extract rowtype info */
    7535         410 :         tupType = HeapTupleHeaderGetTypeId(td);
    7536         410 :         tupTypmod = HeapTupleHeaderGetTypMod(td);
    7537             : 
    7538             :         /* Now, if the target is record not row, maybe we can optimize ... */
    7539         410 :         if (target->dtype == PLPGSQL_DTYPE_REC)
    7540             :         {
    7541         382 :             PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
    7542             : 
    7543             :             /*
    7544             :              * If we already have an expanded record object in the target
    7545             :              * variable, and the source datum has a matching rowtype, then we
    7546             :              * can skip making a new expanded record and just assign the tuple
    7547             :              * with expanded_record_set_tuple.  We consider that there's a
    7548             :              * rowtype match only if it's the same named composite type or
    7549             :              * same registered rowtype.  (Checking to reject an anonymous
    7550             :              * rowtype here should be redundant, but let's be safe.)
    7551             :              */
    7552         496 :             if (rec->erh &&
    7553         204 :                 tupType == rec->erh->er_typeid &&
    7554           2 :                 (tupType != RECORDOID ||
    7555           2 :                  (tupTypmod == rec->erh->er_typmod &&
    7556             :                   tupTypmod >= 0)))
    7557             :             {
    7558          88 :                 expanded_record_set_tuple(rec->erh, &tmptup,
    7559          88 :                                           true, !estate->atomic);
    7560          88 :                 return;
    7561             :             }
    7562             : 
    7563             :             /*
    7564             :              * If the source datum has a rowtype compatible with the target
    7565             :              * variable, just build a new expanded record and assign the tuple
    7566             :              * into it.  Using make_expanded_record_from_typeid() here saves
    7567             :              * one typcache lookup compared to the code below.
    7568             :              */
    7569         294 :             if (rec->rectypeid == RECORDOID || rec->rectypeid == tupType)
    7570             :             {
    7571             :                 ExpandedRecordHeader *newerh;
    7572         212 :                 MemoryContext mcontext = get_eval_mcontext(estate);
    7573             : 
    7574         212 :                 newerh = make_expanded_record_from_typeid(tupType, tupTypmod,
    7575             :                                                           mcontext);
    7576         212 :                 expanded_record_set_tuple(newerh, &tmptup,
    7577         212 :                                           true, !estate->atomic);
    7578         212 :                 assign_record_var(estate, rec, newerh);
    7579         212 :                 return;
    7580             :             }
    7581             : 
    7582             :             /*
    7583             :              * Otherwise, we're going to need conversion, so fall through to
    7584             :              * do it the hard way.
    7585             :              */
    7586             :         }
    7587             : 
    7588             :         /*
    7589             :          * ROW target, or unoptimizable RECORD target, so we have to expend a
    7590             :          * lookup to obtain the source datum's tupdesc.
    7591             :          */
    7592         110 :         tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
    7593             : 
    7594             :         /* Do the move */
    7595         110 :         exec_move_row(estate, target, &tmptup, tupdesc);
    7596             : 
    7597             :         /* Release tupdesc usage count */
    7598          96 :         ReleaseTupleDesc(tupdesc);
    7599             :     }
    7600             : }
    7601             : 
    7602             : /*
    7603             :  * If we have not created an expanded record to hold the record variable's
    7604             :  * value, do so.  The expanded record will be "empty", so this does not
    7605             :  * change the logical state of the record variable: it's still NULL.
    7606             :  * However, now we'll have a tupdesc with which we can e.g. look up fields.
    7607             :  */
    7608             : static void
    7609          72 : instantiate_empty_record_variable(PLpgSQL_execstate *estate, PLpgSQL_rec *rec)
    7610             : {
    7611             :     Assert(rec->erh == NULL);    /* else caller error */
    7612             : 
    7613             :     /* If declared type is RECORD, we can't instantiate */
    7614          72 :     if (rec->rectypeid == RECORDOID)
    7615           4 :         ereport(ERROR,
    7616             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    7617             :                  errmsg("record \"%s\" is not assigned yet", rec->refname),
    7618             :                  errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
    7619             : 
    7620             :     /* Make sure rec->rectypeid is up-to-date before using it */
    7621          68 :     revalidate_rectypeid(rec);
    7622             : 
    7623             :     /* OK, do it */
    7624          66 :     rec->erh = make_expanded_record_from_typeid(rec->rectypeid, -1,
    7625             :                                                 estate->datum_context);
    7626          66 : }
    7627             : 
    7628             : /* ----------
    7629             :  * convert_value_to_string          Convert a non-null Datum to C string
    7630             :  *
    7631             :  * Note: the result is in the estate's eval_mcontext, and will be cleared
    7632             :  * by the next exec_eval_cleanup() call.  The invoked output function might
    7633             :  * leave additional cruft there as well, so just pfree'ing the result string
    7634             :  * would not be enough to avoid memory leaks if we did not do it like this.
    7635             :  * In most usages the Datum being passed in is also in that context (if
    7636             :  * pass-by-reference) and so an exec_eval_cleanup() call is needed anyway.
    7637             :  *
    7638             :  * Note: not caching the conversion function lookup is bad for performance.
    7639             :  * However, this function isn't currently used in any places where an extra
    7640             :  * catalog lookup or two seems like a big deal.
    7641             :  * ----------
    7642             :  */
    7643             : static char *
    7644       23764 : convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
    7645             : {
    7646             :     char       *result;
    7647             :     MemoryContext oldcontext;
    7648             :     Oid         typoutput;
    7649             :     bool        typIsVarlena;
    7650             : 
    7651       23764 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    7652       23764 :     getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
    7653       23764 :     result = OidOutputFunctionCall(typoutput, value);
    7654       23764 :     MemoryContextSwitchTo(oldcontext);
    7655             : 
    7656       23764 :     return result;
    7657             : }
    7658             : 
    7659             : /* ----------
    7660             :  * exec_cast_value          Cast a value if required
    7661             :  *
    7662             :  * Note that *isnull is an input and also an output parameter.  While it's
    7663             :  * unlikely that a cast operation would produce null from non-null or vice
    7664             :  * versa, that could happen in principle.
    7665             :  *
    7666             :  * Note: the estate's eval_mcontext is used for temporary storage, and may
    7667             :  * also contain the result Datum if we have to do a conversion to a pass-
    7668             :  * by-reference data type.  Be sure to do an exec_eval_cleanup() call when
    7669             :  * done with the result.
    7670             :  * ----------
    7671             :  */
    7672             : static Datum
    7673      162472 : exec_cast_value(PLpgSQL_execstate *estate,
    7674             :                 Datum value, bool *isnull,
    7675             :                 Oid valtype, int32 valtypmod,
    7676             :                 Oid reqtype, int32 reqtypmod)
    7677             : {
    7678             :     /*
    7679             :      * If the type of the given value isn't what's requested, convert it.
    7680             :      */
    7681      162472 :     if (valtype != reqtype ||
    7682          24 :         (valtypmod != reqtypmod && reqtypmod != -1))
    7683             :     {
    7684             :         plpgsql_CastHashEntry *cast_entry;
    7685             : 
    7686        4076 :         cast_entry = get_cast_hashentry(estate,
    7687             :                                         valtype, valtypmod,
    7688             :                                         reqtype, reqtypmod);
    7689        4076 :         if (cast_entry)
    7690             :         {
    7691        4076 :             ExprContext *econtext = estate->eval_econtext;
    7692             :             MemoryContext oldcontext;
    7693             : 
    7694        4076 :             oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    7695             : 
    7696        4076 :             econtext->caseValue_datum = value;
    7697        4076 :             econtext->caseValue_isNull = *isnull;
    7698             : 
    7699        4076 :             cast_entry->cast_in_use = true;
    7700             : 
    7701        4076 :             value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
    7702             :                                  isnull);
    7703             : 
    7704        3964 :             cast_entry->cast_in_use = false;
    7705             : 
    7706        3964 :             MemoryContextSwitchTo(oldcontext);
    7707             :         }
    7708             :     }
    7709             : 
    7710      162360 :     return value;
    7711             : }
    7712             : 
    7713             : /* ----------
    7714             :  * get_cast_hashentry           Look up how to perform a type cast
    7715             :  *
    7716             :  * Returns a plpgsql_CastHashEntry if an expression has to be evaluated,
    7717             :  * or NULL if the cast is a mere no-op relabeling.  If there's work to be
    7718             :  * done, the cast_exprstate field contains an expression evaluation tree
    7719             :  * based on a CaseTestExpr input, and the cast_in_use field should be set
    7720             :  * true while executing it.
    7721             :  * ----------
    7722             :  */
    7723             : static plpgsql_CastHashEntry *
    7724        4076 : get_cast_hashentry(PLpgSQL_execstate *estate,
    7725             :                    Oid srctype, int32 srctypmod,
    7726             :                    Oid dsttype, int32 dsttypmod)
    7727             : {
    7728             :     plpgsql_CastHashKey cast_key;
    7729             :     plpgsql_CastHashEntry *cast_entry;
    7730             :     bool        found;
    7731             :     LocalTransactionId curlxid;
    7732             :     MemoryContext oldcontext;
    7733             : 
    7734             :     /* Look for existing entry */
    7735        4076 :     cast_key.srctype = srctype;
    7736        4076 :     cast_key.dsttype = dsttype;
    7737        4076 :     cast_key.srctypmod = srctypmod;
    7738        4076 :     cast_key.dsttypmod = dsttypmod;
    7739        4076 :     cast_entry = (plpgsql_CastHashEntry *) hash_search(estate->cast_hash,
    7740             :                                                        (void *) &cast_key,
    7741             :                                                        HASH_ENTER, &found);
    7742        4076 :     if (!found)                 /* initialize if new entry */
    7743         288 :         cast_entry->cast_cexpr = NULL;
    7744             : 
    7745        7864 :     if (cast_entry->cast_cexpr == NULL ||
    7746        3788 :         !cast_entry->cast_cexpr->is_valid)
    7747             :     {
    7748             :         /*
    7749             :          * We've not looked up this coercion before, or we have but the cached
    7750             :          * expression has been invalidated.
    7751             :          */
    7752             :         Node       *cast_expr;
    7753             :         CachedExpression *cast_cexpr;
    7754             :         CaseTestExpr *placeholder;
    7755             : 
    7756             :         /*
    7757             :          * Drop old cached expression if there is one.
    7758             :          */
    7759         332 :         if (cast_entry->cast_cexpr)
    7760             :         {
    7761          44 :             FreeCachedExpression(cast_entry->cast_cexpr);
    7762          44 :             cast_entry->cast_cexpr = NULL;
    7763             :         }
    7764             : 
    7765             :         /*
    7766             :          * Since we could easily fail (no such coercion), construct a
    7767             :          * temporary coercion expression tree in the short-lived
    7768             :          * eval_mcontext, then if successful save it as a CachedExpression.
    7769             :          */
    7770         332 :         oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    7771             : 
    7772             :         /*
    7773             :          * We use a CaseTestExpr as the base of the coercion tree, since it's
    7774             :          * very cheap to insert the source value for that.
    7775             :          */
    7776         332 :         placeholder = makeNode(CaseTestExpr);
    7777         332 :         placeholder->typeId = srctype;
    7778         332 :         placeholder->typeMod = srctypmod;
    7779         332 :         placeholder->collation = get_typcollation(srctype);
    7780             : 
    7781             :         /*
    7782             :          * Apply coercion.  We use ASSIGNMENT coercion because that's the
    7783             :          * closest match to plpgsql's historical behavior; in particular,
    7784             :          * EXPLICIT coercion would allow silent truncation to a destination
    7785             :          * varchar/bpchar's length, which we do not want.
    7786             :          *
    7787             :          * If source type is UNKNOWN, coerce_to_target_type will fail (it only
    7788             :          * expects to see that for Const input nodes), so don't call it; we'll
    7789             :          * apply CoerceViaIO instead.  Likewise, it doesn't currently work for
    7790             :          * coercing RECORD to some other type, so skip for that too.
    7791             :          */
    7792         332 :         if (srctype == UNKNOWNOID || srctype == RECORDOID)
    7793          84 :             cast_expr = NULL;
    7794             :         else
    7795         248 :             cast_expr = coerce_to_target_type(NULL,
    7796             :                                               (Node *) placeholder, srctype,
    7797             :                                               dsttype, dsttypmod,
    7798             :                                               COERCION_ASSIGNMENT,
    7799             :                                               COERCE_IMPLICIT_CAST,
    7800             :                                               -1);
    7801             : 
    7802             :         /*
    7803             :          * If there's no cast path according to the parser, fall back to using
    7804             :          * an I/O coercion; this is semantically dubious but matches plpgsql's
    7805             :          * historical behavior.  We would need something of the sort for
    7806             :          * UNKNOWN literals in any case.
    7807             :          */
    7808         332 :         if (cast_expr == NULL)
    7809             :         {
    7810         144 :             CoerceViaIO *iocoerce = makeNode(CoerceViaIO);
    7811             : 
    7812         144 :             iocoerce->arg = (Expr *) placeholder;
    7813         144 :             iocoerce->resulttype = dsttype;
    7814         144 :             iocoerce->resultcollid = InvalidOid;
    7815         144 :             iocoerce->coerceformat = COERCE_IMPLICIT_CAST;
    7816         144 :             iocoerce->location = -1;
    7817         144 :             cast_expr = (Node *) iocoerce;
    7818         144 :             if (dsttypmod != -1)
    7819           0 :                 cast_expr = coerce_to_target_type(NULL,
    7820             :                                                   cast_expr, dsttype,
    7821             :                                                   dsttype, dsttypmod,
    7822             :                                                   COERCION_ASSIGNMENT,
    7823             :                                                   COERCE_IMPLICIT_CAST,
    7824             :                                                   -1);
    7825             :         }
    7826             : 
    7827             :         /* Note: we don't bother labeling the expression tree with collation */
    7828             : 
    7829             :         /* Plan the expression and build a CachedExpression */
    7830         332 :         cast_cexpr = GetCachedExpression(cast_expr);
    7831         332 :         cast_expr = cast_cexpr->expr;
    7832             : 
    7833             :         /* Detect whether we have a no-op (RelabelType) coercion */
    7834         354 :         if (IsA(cast_expr, RelabelType) &&
    7835          22 :             ((RelabelType *) cast_expr)->arg == (Expr *) placeholder)
    7836           0 :             cast_expr = NULL;
    7837             : 
    7838             :         /* Now we can fill in the hashtable entry. */
    7839         332 :         cast_entry->cast_cexpr = cast_cexpr;
    7840         332 :         cast_entry->cast_expr = (Expr *) cast_expr;
    7841         332 :         cast_entry->cast_exprstate = NULL;
    7842         332 :         cast_entry->cast_in_use = false;
    7843         332 :         cast_entry->cast_lxid = InvalidLocalTransactionId;
    7844             : 
    7845         332 :         MemoryContextSwitchTo(oldcontext);
    7846             :     }
    7847             : 
    7848             :     /* Done if we have determined that this is a no-op cast. */
    7849        4076 :     if (cast_entry->cast_expr == NULL)
    7850           0 :         return NULL;
    7851             : 
    7852             :     /*
    7853             :      * Prepare the expression for execution, if it's not been done already in
    7854             :      * the current transaction; also, if it's marked busy in the current
    7855             :      * transaction, abandon that expression tree and build a new one, so as to
    7856             :      * avoid potential problems with recursive cast expressions and failed
    7857             :      * executions.  (We will leak some memory intra-transaction if that
    7858             :      * happens a lot, but we don't expect it to.)  It's okay to update the
    7859             :      * hash table with the new tree because all plpgsql functions within a
    7860             :      * given transaction share the same simple_eval_estate.  (Well, regular
    7861             :      * functions do; DO blocks have private simple_eval_estates, and private
    7862             :      * cast hash tables to go with them.)
    7863             :      */
    7864        4076 :     curlxid = MyProc->lxid;
    7865        4076 :     if (cast_entry->cast_lxid != curlxid || cast_entry->cast_in_use)
    7866             :     {
    7867        1224 :         oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
    7868        1224 :         cast_entry->cast_exprstate = ExecInitExpr(cast_entry->cast_expr, NULL);
    7869        1224 :         cast_entry->cast_in_use = false;
    7870        1224 :         cast_entry->cast_lxid = curlxid;
    7871        1224 :         MemoryContextSwitchTo(oldcontext);
    7872             :     }
    7873             : 
    7874        4076 :     return cast_entry;
    7875             : }
    7876             : 
    7877             : 
    7878             : /* ----------
    7879             :  * exec_simple_check_plan -     Check if a plan is simple enough to
    7880             :  *                              be evaluated by ExecEvalExpr() instead
    7881             :  *                              of SPI.
    7882             :  * ----------
    7883             :  */
    7884             : static void
    7885       10400 : exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
    7886             : {
    7887             :     List       *plansources;
    7888             :     CachedPlanSource *plansource;
    7889             :     Query      *query;
    7890             :     CachedPlan *cplan;
    7891             :     MemoryContext oldcontext;
    7892             : 
    7893             :     /*
    7894             :      * Initialize to "not simple".
    7895             :      */
    7896       10400 :     expr->expr_simple_expr = NULL;
    7897             : 
    7898             :     /*
    7899             :      * Check the analyzed-and-rewritten form of the query to see if we will be
    7900             :      * able to treat it as a simple expression.  Since this function is only
    7901             :      * called immediately after creating the CachedPlanSource, we need not
    7902             :      * worry about the query being stale.
    7903             :      */
    7904             : 
    7905             :     /*
    7906             :      * We can only test queries that resulted in exactly one CachedPlanSource
    7907             :      */
    7908       10400 :     plansources = SPI_plan_get_plan_sources(expr->plan);
    7909       10400 :     if (list_length(plansources) != 1)
    7910           0 :         return;
    7911       10400 :     plansource = (CachedPlanSource *) linitial(plansources);
    7912             : 
    7913             :     /*
    7914             :      * 1. There must be one single querytree.
    7915             :      */
    7916       10400 :     if (list_length(plansource->query_list) != 1)
    7917           0 :         return;
    7918       10400 :     query = (Query *) linitial(plansource->query_list);
    7919             : 
    7920             :     /*
    7921             :      * 2. It must be a plain SELECT query without any input tables
    7922             :      */
    7923       10400 :     if (!IsA(query, Query))
    7924           0 :         return;
    7925       10400 :     if (query->commandType != CMD_SELECT)
    7926         514 :         return;
    7927        9886 :     if (query->rtable != NIL)
    7928         558 :         return;
    7929             : 
    7930             :     /*
    7931             :      * 3. Can't have any subplans, aggregates, qual clauses either.  (These
    7932             :      * tests should generally match what inline_function() checks before
    7933             :      * inlining a SQL function; otherwise, inlining could change our
    7934             :      * conclusion about whether an expression is simple, which we don't want.)
    7935             :      */
    7936       18656 :     if (query->hasAggs ||
    7937       18656 :         query->hasWindowFuncs ||
    7938       18652 :         query->hasTargetSRFs ||
    7939       18428 :         query->hasSubLinks ||
    7940       18208 :         query->cteList ||
    7941       18208 :         query->jointree->fromlist ||
    7942       18208 :         query->jointree->quals ||
    7943       18208 :         query->groupClause ||
    7944       18208 :         query->groupingSets ||
    7945       18208 :         query->havingQual ||
    7946       18208 :         query->windowClause ||
    7947       18208 :         query->distinctClause ||
    7948       18208 :         query->sortClause ||
    7949       18208 :         query->limitOffset ||
    7950       18208 :         query->limitCount ||
    7951        9104 :         query->setOperations)
    7952         224 :         return;
    7953             : 
    7954             :     /*
    7955             :      * 4. The query must have a single attribute as result
    7956             :      */
    7957        9104 :     if (list_length(query->targetList) != 1)
    7958          70 :         return;
    7959             : 
    7960             :     /*
    7961             :      * OK, we can treat it as a simple plan.
    7962             :      *
    7963             :      * Get the generic plan for the query.  If replanning is needed, do that
    7964             :      * work in the eval_mcontext.
    7965             :      */
    7966        9034 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    7967        9034 :     cplan = SPI_plan_get_cached_plan(expr->plan);
    7968        9012 :     MemoryContextSwitchTo(oldcontext);
    7969             : 
    7970             :     /* Can't fail, because we checked for a single CachedPlanSource above */
    7971             :     Assert(cplan != NULL);
    7972             : 
    7973             :     /* Share the remaining work with replan code path */
    7974        9012 :     exec_save_simple_expr(expr, cplan);
    7975             : 
    7976             :     /* Release our plan refcount */
    7977        9012 :     ReleaseCachedPlan(cplan, true);
    7978             : }
    7979             : 
    7980             : /*
    7981             :  * exec_save_simple_expr --- extract simple expression from CachedPlan
    7982             :  */
    7983             : static void
    7984       10708 : exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
    7985             : {
    7986             :     PlannedStmt *stmt;
    7987             :     Plan       *plan;
    7988             :     Expr       *tle_expr;
    7989             : 
    7990             :     /*
    7991             :      * Given the checks that exec_simple_check_plan did, none of the Asserts
    7992             :      * here should ever fail.
    7993             :      */
    7994             : 
    7995             :     /* Extract the single PlannedStmt */
    7996             :     Assert(list_length(cplan->stmt_list) == 1);
    7997       10708 :     stmt = linitial_node(PlannedStmt, cplan->stmt_list);
    7998             :     Assert(stmt->commandType == CMD_SELECT);
    7999             : 
    8000             :     /*
    8001             :      * Ordinarily, the plan node should be a simple Result.  However, if
    8002             :      * force_parallel_mode is on, the planner might've stuck a Gather node
    8003             :      * atop that.  The simplest way to deal with this is to look through the
    8004             :      * Gather node.  The Gather node's tlist would normally contain a Var
    8005             :      * referencing the child node's output, but it could also be a Param, or
    8006             :      * it could be a Const that setrefs.c copied as-is.
    8007             :      */
    8008       10708 :     plan = stmt->planTree;
    8009             :     for (;;)
    8010             :     {
    8011             :         /* Extract the single tlist expression */
    8012           0 :         Assert(list_length(plan->targetlist) == 1);
    8013       10708 :         tle_expr = castNode(TargetEntry, linitial(plan->targetlist))->expr;
    8014             : 
    8015       10708 :         if (IsA(plan, Result))
    8016             :         {
    8017             :             Assert(plan->lefttree == NULL &&
    8018             :                    plan->righttree == NULL &&
    8019             :                    plan->initPlan == NULL &&
    8020             :                    plan->qual == NULL &&
    8021             :                    ((Result *) plan)->resconstantqual == NULL);
    8022       10708 :             break;
    8023             :         }
    8024           0 :         else if (IsA(plan, Gather))
    8025             :         {
    8026             :             Assert(plan->lefttree != NULL &&
    8027             :                    plan->righttree == NULL &&
    8028             :                    plan->initPlan == NULL &&
    8029             :                    plan->qual == NULL);
    8030             :             /* If setrefs.c copied up a Const, no need to look further */
    8031           0 :             if (IsA(tle_expr, Const))
    8032           0 :                 break;
    8033             :             /* Otherwise, it had better be a Param or an outer Var */
    8034             :             Assert(IsA(tle_expr, Param) ||(IsA(tle_expr, Var) &&
    8035             :                                            ((Var *) tle_expr)->varno == OUTER_VAR));
    8036             :             /* Descend to the child node */
    8037           0 :             plan = plan->lefttree;
    8038             :         }
    8039             :         else
    8040           0 :             elog(ERROR, "unexpected plan node type: %d",
    8041             :                  (int) nodeTag(plan));
    8042             :     }
    8043             : 
    8044             :     /*
    8045             :      * Save the simple expression, and initialize state to "not valid in
    8046             :      * current transaction".
    8047             :      */
    8048       10708 :     expr->expr_simple_expr = tle_expr;
    8049       10708 :     expr->expr_simple_generation = cplan->generation;
    8050       10708 :     expr->expr_simple_state = NULL;
    8051       10708 :     expr->expr_simple_in_use = false;
    8052       10708 :     expr->expr_simple_lxid = InvalidLocalTransactionId;
    8053             :     /* Also stash away the expression result type */
    8054       10708 :     expr->expr_simple_type = exprType((Node *) tle_expr);
    8055       10708 :     expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
    8056       10708 : }
    8057             : 
    8058             : /*
    8059             :  * exec_check_rw_parameter --- can we pass expanded object as read/write param?
    8060             :  *
    8061             :  * If we have an assignment like "x := array_append(x, foo)" in which the
    8062             :  * top-level function is trusted not to corrupt its argument in case of an
    8063             :  * error, then when x has an expanded object as value, it is safe to pass the
    8064             :  * value as a read/write pointer and let the function modify the value
    8065             :  * in-place.
    8066             :  *
    8067             :  * This function checks for a safe expression, and sets expr->rwparam to the
    8068             :  * dno of the target variable (x) if safe, or -1 if not safe.
    8069             :  */
    8070             : static void
    8071        1468 : exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno)
    8072             : {
    8073             :     Oid         funcid;
    8074             :     List       *fargs;
    8075             :     ListCell   *lc;
    8076             : 
    8077             :     /* Assume unsafe */
    8078        1468 :     expr->rwparam = -1;
    8079             : 
    8080             :     /*
    8081             :      * If the expression isn't simple, there's no point in trying to optimize
    8082             :      * (because the exec_run_select code path will flatten any expanded result
    8083             :      * anyway).  Even without that, this seems like a good safety restriction.
    8084             :      */
    8085        1468 :     if (expr->expr_simple_expr == NULL)
    8086          34 :         return;
    8087             : 
    8088             :     /*
    8089             :      * If target variable isn't referenced by expression, no need to look
    8090             :      * further.
    8091             :      */
    8092        1434 :     if (!bms_is_member(target_dno, expr->paramnos))
    8093        1054 :         return;
    8094             : 
    8095             :     /*
    8096             :      * Top level of expression must be a simple FuncExpr or OpExpr.
    8097             :      */
    8098         380 :     if (IsA(expr->expr_simple_expr, FuncExpr))
    8099             :     {
    8100          64 :         FuncExpr   *fexpr = (FuncExpr *) expr->expr_simple_expr;
    8101             : 
    8102          64 :         funcid = fexpr->funcid;
    8103          64 :         fargs = fexpr->args;
    8104             :     }
    8105         316 :     else if (IsA(expr->expr_simple_expr, OpExpr))
    8106             :     {
    8107         316 :         OpExpr     *opexpr = (OpExpr *) expr->expr_simple_expr;
    8108             : 
    8109         316 :         funcid = opexpr->opfuncid;
    8110         316 :         fargs = opexpr->args;
    8111             :     }
    8112             :     else
    8113           0 :         return;
    8114             : 
    8115             :     /*
    8116             :      * The top-level function must be one that we trust to be "safe".
    8117             :      * Currently we hard-wire the list, but it would be very desirable to
    8118             :      * allow extensions to mark their functions as safe ...
    8119             :      */
    8120         380 :     if (!(funcid == F_ARRAY_APPEND ||
    8121             :           funcid == F_ARRAY_PREPEND))
    8122         324 :         return;
    8123             : 
    8124             :     /*
    8125             :      * The target variable (in the form of a Param) must only appear as a
    8126             :      * direct argument of the top-level function.
    8127             :      */
    8128         156 :     foreach(lc, fargs)
    8129             :     {
    8130         108 :         Node       *arg = (Node *) lfirst(lc);
    8131             : 
    8132             :         /* A Param is OK, whether it's the target variable or not */
    8133         108 :         if (arg && IsA(arg, Param))
    8134          48 :             continue;
    8135             :         /* Otherwise, argument expression must not reference target */
    8136          60 :         if (contains_target_param(arg, &target_dno))
    8137          16 :             return;
    8138             :     }
    8139             : 
    8140             :     /* OK, we can pass target as a read-write parameter */
    8141          48 :     expr->rwparam = target_dno;
    8142             : }
    8143             : 
    8144             : /*
    8145             :  * Recursively check for a Param referencing the target variable
    8146             :  */
    8147             : static bool
    8148         156 : contains_target_param(Node *node, int *target_dno)
    8149             : {
    8150         156 :     if (node == NULL)
    8151           0 :         return false;
    8152         156 :     if (IsA(node, Param))
    8153             :     {
    8154          52 :         Param      *param = (Param *) node;
    8155             : 
    8156         104 :         if (param->paramkind == PARAM_EXTERN &&
    8157          52 :             param->paramid == *target_dno + 1)
    8158           8 :             return true;
    8159          44 :         return false;
    8160             :     }
    8161         104 :     return expression_tree_walker(node, contains_target_param,
    8162             :                                   (void *) target_dno);
    8163             : }
    8164             : 
    8165             : /* ----------
    8166             :  * exec_set_found           Set the global found variable to true/false
    8167             :  * ----------
    8168             :  */
    8169             : static void
    8170       77376 : exec_set_found(PLpgSQL_execstate *estate, bool state)
    8171             : {
    8172             :     PLpgSQL_var *var;
    8173             : 
    8174       77376 :     var = (PLpgSQL_var *) (estate->datums[estate->found_varno]);
    8175       77376 :     assign_simple_var(estate, var, BoolGetDatum(state), false, false);
    8176       77376 : }
    8177             : 
    8178             : /*
    8179             :  * plpgsql_create_econtext --- create an eval_econtext for the current function
    8180             :  *
    8181             :  * We may need to create a new shared_simple_eval_estate too, if there's not
    8182             :  * one already for the current transaction.  The EState will be cleaned up at
    8183             :  * transaction end.
    8184             :  */
    8185             : static void
    8186       73368 : plpgsql_create_econtext(PLpgSQL_execstate *estate)
    8187             : {
    8188             :     SimpleEcontextStackEntry *entry;
    8189             : 
    8190             :     /*
    8191             :      * Create an EState for evaluation of simple expressions, if there's not
    8192             :      * one already in the current transaction.  The EState is made a child of
    8193             :      * TopTransactionContext so it will have the right lifespan.
    8194             :      *
    8195             :      * Note that this path is never taken when executing a DO block; the
    8196             :      * required EState was already made by plpgsql_inline_handler.
    8197             :      */
    8198       73368 :     if (estate->simple_eval_estate == NULL)
    8199             :     {
    8200             :         MemoryContext oldcontext;
    8201             : 
    8202        9010 :         if (shared_simple_eval_estate == NULL)
    8203             :         {
    8204        9004 :             oldcontext = MemoryContextSwitchTo(TopTransactionContext);
    8205        9004 :             shared_simple_eval_estate = CreateExecutorState();
    8206        9004 :             MemoryContextSwitchTo(oldcontext);
    8207             :         }
    8208        9010 :         estate->simple_eval_estate = shared_simple_eval_estate;
    8209             :     }
    8210             : 
    8211             :     /*
    8212             :      * Create a child econtext for the current function.
    8213             :      */
    8214       73368 :     estate->eval_econtext = CreateExprContext(estate->simple_eval_estate);
    8215             : 
    8216             :     /*
    8217             :      * Make a stack entry so we can clean up the econtext at subxact end.
    8218             :      * Stack entries are kept in TopTransactionContext for simplicity.
    8219             :      */
    8220       73368 :     entry = (SimpleEcontextStackEntry *)
    8221       73368 :         MemoryContextAlloc(TopTransactionContext,
    8222             :                            sizeof(SimpleEcontextStackEntry));
    8223             : 
    8224       73368 :     entry->stack_econtext = estate->eval_econtext;
    8225       73368 :     entry->xact_subxid = GetCurrentSubTransactionId();
    8226             : 
    8227       73368 :     entry->next = simple_econtext_stack;
    8228       73368 :     simple_econtext_stack = entry;
    8229       73368 : }
    8230             : 
    8231             : /*
    8232             :  * plpgsql_destroy_econtext --- destroy function's econtext
    8233             :  *
    8234             :  * We check that it matches the top stack entry, and destroy the stack
    8235             :  * entry along with the context.
    8236             :  */
    8237             : static void
    8238       64556 : plpgsql_destroy_econtext(PLpgSQL_execstate *estate)
    8239             : {
    8240             :     SimpleEcontextStackEntry *next;
    8241             : 
    8242             :     Assert(simple_econtext_stack != NULL);
    8243             :     Assert(simple_econtext_stack->stack_econtext == estate->eval_econtext);
    8244             : 
    8245       64556 :     next = simple_econtext_stack->next;
    8246       64556 :     pfree(simple_econtext_stack);
    8247       64556 :     simple_econtext_stack = next;
    8248             : 
    8249       64556 :     FreeExprContext(estate->eval_econtext, true);
    8250       64556 :     estate->eval_econtext = NULL;
    8251       64556 : }
    8252             : 
    8253             : /*
    8254             :  * plpgsql_xact_cb --- post-transaction-commit-or-abort cleanup
    8255             :  *
    8256             :  * If a simple-expression EState was created in the current transaction,
    8257             :  * it has to be cleaned up.
    8258             :  */
    8259             : void
    8260      233500 : plpgsql_xact_cb(XactEvent event, void *arg)
    8261             : {
    8262             :     /*
    8263             :      * If we are doing a clean transaction shutdown, free the EState (so that
    8264             :      * any remaining resources will be released correctly). In an abort, we
    8265             :      * expect the regular abort recovery procedures to release everything of
    8266             :      * interest.
    8267             :      */
    8268      233500 :     if (event == XACT_EVENT_COMMIT || event == XACT_EVENT_PREPARE)
    8269             :     {
    8270      112918 :         simple_econtext_stack = NULL;
    8271             : 
    8272      112918 :         if (shared_simple_eval_estate)
    8273        8302 :             FreeExecutorState(shared_simple_eval_estate);
    8274      112918 :         shared_simple_eval_estate = NULL;
    8275             :     }
    8276      120582 :     else if (event == XACT_EVENT_ABORT)
    8277             :     {
    8278        4782 :         simple_econtext_stack = NULL;
    8279        4782 :         shared_simple_eval_estate = NULL;
    8280             :     }
    8281      233500 : }
    8282             : 
    8283             : /*
    8284             :  * plpgsql_subxact_cb --- post-subtransaction-commit-or-abort cleanup
    8285             :  *
    8286             :  * Make sure any simple-expression econtexts created in the current
    8287             :  * subtransaction get cleaned up.  We have to do this explicitly because
    8288             :  * no other code knows which econtexts belong to which level of subxact.
    8289             :  */
    8290             : void
    8291       12260 : plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid,
    8292             :                    SubTransactionId parentSubid, void *arg)
    8293             : {
    8294       12260 :     if (event == SUBXACT_EVENT_COMMIT_SUB || event == SUBXACT_EVENT_ABORT_SUB)
    8295             :     {
    8296       21750 :         while (simple_econtext_stack != NULL &&
    8297        8172 :                simple_econtext_stack->xact_subxid == mySubid)
    8298             :         {
    8299             :             SimpleEcontextStackEntry *next;
    8300             : 
    8301        4174 :             FreeExprContext(simple_econtext_stack->stack_econtext,
    8302             :                             (event == SUBXACT_EVENT_COMMIT_SUB));
    8303        4174 :             next = simple_econtext_stack->next;
    8304        4174 :             pfree(simple_econtext_stack);
    8305        4174 :             simple_econtext_stack = next;
    8306             :         }
    8307             :     }
    8308       12260 : }
    8309             : 
    8310             : /*
    8311             :  * assign_simple_var --- assign a new value to any VAR datum.
    8312             :  *
    8313             :  * This should be the only mechanism for assignment to simple variables,
    8314             :  * lest we do the release of the old value incorrectly (not to mention
    8315             :  * the detoasting business).
    8316             :  */
    8317             : static void
    8318      218190 : assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var,
    8319             :                   Datum newvalue, bool isnull, bool freeable)
    8320             : {
    8321             :     Assert(var->dtype == PLPGSQL_DTYPE_VAR ||
    8322             :            var->dtype == PLPGSQL_DTYPE_PROMISE);
    8323             : 
    8324             :     /*
    8325             :      * In non-atomic contexts, we do not want to store TOAST pointers in
    8326             :      * variables, because such pointers might become stale after a commit.
    8327             :      * Forcibly detoast in such cases.  We don't want to detoast (flatten)
    8328             :      * expanded objects, however; those should be OK across a transaction
    8329             :      * boundary since they're just memory-resident objects.  (Elsewhere in
    8330             :      * this module, operations on expanded records likewise need to request
    8331             :      * detoasting of record fields when !estate->atomic.  Expanded arrays are
    8332             :      * not a problem since all array entries are always detoasted.)
    8333             :      */
    8334      232464 :     if (!estate->atomic && !isnull && var->datatype->typlen == -1 &&
    8335       17484 :         VARATT_IS_EXTERNAL_NON_EXPANDED(DatumGetPointer(newvalue)))
    8336             :     {
    8337             :         MemoryContext oldcxt;
    8338             :         Datum       detoasted;
    8339             : 
    8340             :         /*
    8341             :          * Do the detoasting in the eval_mcontext to avoid long-term leakage
    8342             :          * of whatever memory toast fetching might leak.  Then we have to copy
    8343             :          * the detoasted datum to the function's main context, which is a
    8344             :          * pain, but there's little choice.
    8345             :          */
    8346           4 :         oldcxt = MemoryContextSwitchTo(get_eval_mcontext(estate));
    8347           4 :         detoasted = PointerGetDatum(heap_tuple_fetch_attr((struct varlena *) DatumGetPointer(newvalue)));
    8348           4 :         MemoryContextSwitchTo(oldcxt);
    8349             :         /* Now's a good time to not leak the input value if it's freeable */
    8350           4 :         if (freeable)
    8351           4 :             pfree(DatumGetPointer(newvalue));
    8352             :         /* Once we copy the value, it's definitely freeable */
    8353           4 :         newvalue = datumCopy(detoasted, false, -1);
    8354           4 :         freeable = true;
    8355             :         /* Can't clean up eval_mcontext here, but it'll happen before long */
    8356             :     }
    8357             : 
    8358             :     /* Free the old value if needed */
    8359      218190 :     if (var->freeval)
    8360             :     {
    8361       19616 :         if (DatumIsReadWriteExpandedObject(var->value,
    8362             :                                            var->isnull,
    8363             :                                            var->datatype->typlen))
    8364        3176 :             DeleteExpandedObject(var->value);
    8365             :         else
    8366       16440 :             pfree(DatumGetPointer(var->value));
    8367             :     }
    8368             :     /* Assign new value to datum */
    8369      218190 :     var->value = newvalue;
    8370      218190 :     var->isnull = isnull;
    8371      218190 :     var->freeval = freeable;
    8372             : 
    8373             :     /*
    8374             :      * If it's a promise variable, then either we just assigned the promised
    8375             :      * value, or the user explicitly assigned an overriding value.  Either
    8376             :      * way, cancel the promise.
    8377             :      */
    8378      218190 :     var->promise = PLPGSQL_PROMISE_NONE;
    8379      218190 : }
    8380             : 
    8381             : /*
    8382             :  * free old value of a text variable and assign new value from C string
    8383             :  */
    8384             : static void
    8385        7288 : assign_text_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, const char *str)
    8386             : {
    8387        7288 :     assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
    8388        7288 : }
    8389             : 
    8390             : /*
    8391             :  * assign_record_var --- assign a new value to any REC datum.
    8392             :  */
    8393             : static void
    8394        2704 : assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec,
    8395             :                   ExpandedRecordHeader *erh)
    8396             : {
    8397             :     Assert(rec->dtype == PLPGSQL_DTYPE_REC);
    8398             : 
    8399             :     /* Transfer new record object into datum_context */
    8400        2704 :     TransferExpandedRecord(erh, estate->datum_context);
    8401             : 
    8402             :     /* Free the old value ... */
    8403        2704 :     if (rec->erh)
    8404         210 :         DeleteExpandedObject(ExpandedRecordGetDatum(rec->erh));
    8405             : 
    8406             :     /* ... and install the new */
    8407        2704 :     rec->erh = erh;
    8408        2704 : }
    8409             : 
    8410             : /*
    8411             :  * exec_eval_using_params --- evaluate params of USING clause
    8412             :  *
    8413             :  * The result data structure is created in the stmt_mcontext, and should
    8414             :  * be freed by resetting that context.
    8415             :  */
    8416             : static PreparedParamsData *
    8417         136 : exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
    8418             : {
    8419             :     PreparedParamsData *ppd;
    8420         136 :     MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
    8421             :     int         nargs;
    8422             :     int         i;
    8423             :     ListCell   *lc;
    8424             : 
    8425         136 :     ppd = (PreparedParamsData *)
    8426             :         MemoryContextAlloc(stmt_mcontext, sizeof(PreparedParamsData));
    8427         136 :     nargs = list_length(params);
    8428             : 
    8429         136 :     ppd->nargs = nargs;
    8430         136 :     ppd->types = (Oid *)
    8431         136 :         MemoryContextAlloc(stmt_mcontext, nargs * sizeof(Oid));
    8432         136 :     ppd->values = (Datum *)
    8433         136 :         MemoryContextAlloc(stmt_mcontext, nargs * sizeof(Datum));
    8434         136 :     ppd->nulls = (char *)
    8435         136 :         MemoryContextAlloc(stmt_mcontext, nargs * sizeof(char));
    8436             : 
    8437         136 :     i = 0;
    8438         396 :     foreach(lc, params)
    8439             :     {
    8440         260 :         PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
    8441             :         bool        isnull;
    8442             :         int32       ppdtypmod;
    8443             :         MemoryContext oldcontext;
    8444             : 
    8445         520 :         ppd->values[i] = exec_eval_expr(estate, param,
    8446             :                                         &isnull,
    8447         260 :                                         &ppd->types[i],
    8448             :                                         &ppdtypmod);
    8449         260 :         ppd->nulls[i] = isnull ? 'n' : ' ';
    8450             : 
    8451         260 :         oldcontext = MemoryContextSwitchTo(stmt_mcontext);
    8452             : 
    8453         260 :         if (ppd->types[i] == UNKNOWNOID)
    8454             :         {
    8455             :             /*
    8456             :              * Treat 'unknown' parameters as text, since that's what most
    8457             :              * people would expect. SPI_execute_with_args can coerce unknown
    8458             :              * constants in a more intelligent way, but not unknown Params.
    8459             :              * This code also takes care of copying into the right context.
    8460             :              * Note we assume 'unknown' has the representation of C-string.
    8461             :              */
    8462           0 :             ppd->types[i] = TEXTOID;
    8463           0 :             if (!isnull)
    8464           0 :                 ppd->values[i] = CStringGetTextDatum(DatumGetCString(ppd->values[i]));
    8465             :         }
    8466             :         /* pass-by-ref non null values must be copied into stmt_mcontext */
    8467         260 :         else if (!isnull)
    8468             :         {
    8469             :             int16       typLen;
    8470             :             bool        typByVal;
    8471             : 
    8472         260 :             get_typlenbyval(ppd->types[i], &typLen, &typByVal);
    8473         260 :             if (!typByVal)
    8474         232 :                 ppd->values[i] = datumCopy(ppd->values[i], typByVal, typLen);
    8475             :         }
    8476             : 
    8477         260 :         MemoryContextSwitchTo(oldcontext);
    8478             : 
    8479         260 :         exec_eval_cleanup(estate);
    8480             : 
    8481         260 :         i++;
    8482             :     }
    8483             : 
    8484         136 :     return ppd;
    8485             : }
    8486             : 
    8487             : /*
    8488             :  * Open portal for dynamic query
    8489             :  *
    8490             :  * Caution: this resets the stmt_mcontext at exit.  We might eventually need
    8491             :  * to move that responsibility to the callers, but currently no caller needs
    8492             :  * to have statement-lifetime temp data that survives past this, so it's
    8493             :  * simpler to do it here.
    8494             :  */
    8495             : static Portal
    8496        2410 : exec_dynquery_with_params(PLpgSQL_execstate *estate,
    8497             :                           PLpgSQL_expr *dynquery,
    8498             :                           List *params,
    8499             :                           const char *portalname,
    8500             :                           int cursorOptions)
    8501             : {
    8502             :     Portal      portal;
    8503             :     Datum       query;
    8504             :     bool        isnull;
    8505             :     Oid         restype;
    8506             :     int32       restypmod;
    8507             :     char       *querystr;
    8508        2410 :     MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
    8509             : 
    8510             :     /*
    8511             :      * Evaluate the string expression after the EXECUTE keyword. Its result is
    8512             :      * the querystring we have to execute.
    8513             :      */
    8514        2410 :     query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
    8515        2410 :     if (isnull)
    8516           0 :         ereport(ERROR,
    8517             :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    8518             :                  errmsg("query string argument of EXECUTE is null")));
    8519             : 
    8520             :     /* Get the C-String representation */
    8521        2410 :     querystr = convert_value_to_string(estate, query, restype);
    8522             : 
    8523             :     /* copy it into the stmt_mcontext before we clean up */
    8524        2410 :     querystr = MemoryContextStrdup(stmt_mcontext, querystr);
    8525             : 
    8526        2410 :     exec_eval_cleanup(estate);
    8527             : 
    8528             :     /*
    8529             :      * Open an implicit cursor for the query.  We use
    8530             :      * SPI_cursor_open_with_args even when there are no params, because this
    8531             :      * avoids making and freeing one copy of the plan.
    8532             :      */
    8533        2410 :     if (params)
    8534             :     {
    8535             :         PreparedParamsData *ppd;
    8536             : 
    8537          12 :         ppd = exec_eval_using_params(estate, params);
    8538          24 :         portal = SPI_cursor_open_with_args(portalname,
    8539             :                                            querystr,
    8540             :                                            ppd->nargs, ppd->types,
    8541          12 :                                            ppd->values, ppd->nulls,
    8542          12 :                                            estate->readonly_func,
    8543             :                                            cursorOptions);
    8544             :     }
    8545             :     else
    8546             :     {
    8547        2398 :         portal = SPI_cursor_open_with_args(portalname,
    8548             :                                            querystr,
    8549             :                                            0, NULL,
    8550             :                                            NULL, NULL,
    8551        2398 :                                            estate->readonly_func,
    8552             :                                            cursorOptions);
    8553             :     }
    8554             : 
    8555        2410 :     if (portal == NULL)
    8556           0 :         elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
    8557             :              querystr, SPI_result_code_string(SPI_result));
    8558             : 
    8559             :     /* Release transient data */
    8560        2410 :     MemoryContextReset(stmt_mcontext);
    8561             : 
    8562        2410 :     return portal;
    8563             : }
    8564             : 
    8565             : /*
    8566             :  * Return a formatted string with information about an expression's parameters,
    8567             :  * or NULL if the expression does not take any parameters.
    8568             :  * The result is in the eval_mcontext.
    8569             :  */
    8570             : static char *
    8571          16 : format_expr_params(PLpgSQL_execstate *estate,
    8572             :                    const PLpgSQL_expr *expr)
    8573             : {
    8574             :     int         paramno;
    8575             :     int         dno;
    8576             :     StringInfoData paramstr;
    8577             :     MemoryContext oldcontext;
    8578             : 
    8579          16 :     if (!expr->paramnos)
    8580           4 :         return NULL;
    8581             : 
    8582          12 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    8583             : 
    8584          12 :     initStringInfo(&paramstr);
    8585          12 :     paramno = 0;
    8586          12 :     dno = -1;
    8587          48 :     while ((dno = bms_next_member(expr->paramnos, dno)) >= 0)
    8588             :     {
    8589             :         Datum       paramdatum;
    8590             :         Oid         paramtypeid;
    8591             :         bool        paramisnull;
    8592             :         int32       paramtypmod;
    8593             :         PLpgSQL_var *curvar;
    8594             : 
    8595          24 :         curvar = (PLpgSQL_var *) estate->datums[dno];
    8596             : 
    8597          24 :         exec_eval_datum(estate, (PLpgSQL_datum *) curvar,
    8598             :                         &paramtypeid, &paramtypmod,
    8599             :                         &paramdatum, &paramisnull);
    8600             : 
    8601          24 :         appendStringInfo(&paramstr, "%s%s = ",
    8602             :                          paramno > 0 ? ", " : "",
    8603             :                          curvar->refname);
    8604             : 
    8605          24 :         if (paramisnull)
    8606           0 :             appendStringInfoString(&paramstr, "NULL");
    8607             :         else
    8608             :         {
    8609          24 :             char       *value = convert_value_to_string(estate, paramdatum, paramtypeid);
    8610             :             char       *p;
    8611             : 
    8612          24 :             appendStringInfoCharMacro(&paramstr, '\'');
    8613          72 :             for (p = value; *p; p++)
    8614             :             {
    8615          48 :                 if (*p == '\'') /* double single quotes */
    8616           0 :                     appendStringInfoCharMacro(&paramstr, *p);
    8617          48 :                 appendStringInfoCharMacro(&paramstr, *p);
    8618             :             }
    8619          24 :             appendStringInfoCharMacro(&paramstr, '\'');
    8620             :         }
    8621             : 
    8622          24 :         paramno++;
    8623             :     }
    8624             : 
    8625          12 :     MemoryContextSwitchTo(oldcontext);
    8626             : 
    8627          12 :     return paramstr.data;
    8628             : }
    8629             : 
    8630             : /*
    8631             :  * Return a formatted string with information about PreparedParamsData, or NULL
    8632             :  * if there are no parameters.
    8633             :  * The result is in the eval_mcontext.
    8634             :  */
    8635             : static char *
    8636          12 : format_preparedparamsdata(PLpgSQL_execstate *estate,
    8637             :                           const PreparedParamsData *ppd)
    8638             : {
    8639             :     int         paramno;
    8640             :     StringInfoData paramstr;
    8641             :     MemoryContext oldcontext;
    8642             : 
    8643          12 :     if (!ppd)
    8644           4 :         return NULL;
    8645             : 
    8646           8 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    8647             : 
    8648           8 :     initStringInfo(&paramstr);
    8649          20 :     for (paramno = 0; paramno < ppd->nargs; paramno++)
    8650             :     {
    8651          12 :         appendStringInfo(&paramstr, "%s$%d = ",
    8652             :                          paramno > 0 ? ", " : "",
    8653             :                          paramno + 1);
    8654             : 
    8655          12 :         if (ppd->nulls[paramno] == 'n')
    8656           0 :             appendStringInfoString(&paramstr, "NULL");
    8657             :         else
    8658             :         {
    8659          12 :             char       *value = convert_value_to_string(estate, ppd->values[paramno], ppd->types[paramno]);
    8660             :             char       *p;
    8661             : 
    8662          12 :             appendStringInfoCharMacro(&paramstr, '\'');
    8663          32 :             for (p = value; *p; p++)
    8664             :             {
    8665          20 :                 if (*p == '\'') /* double single quotes */
    8666           0 :                     appendStringInfoCharMacro(&paramstr, *p);
    8667          20 :                 appendStringInfoCharMacro(&paramstr, *p);
    8668             :             }
    8669          12 :             appendStringInfoCharMacro(&paramstr, '\'');
    8670             :         }
    8671             :     }
    8672             : 
    8673           8 :     MemoryContextSwitchTo(oldcontext);
    8674             : 
    8675           8 :     return paramstr.data;
    8676             : }

Generated by: LCOV version 1.13