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

Generated by: LCOV version 2.0-1