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

Generated by: LCOV version 2.0-1