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-04-04 15:16:22 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        43242 : 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        43242 :     plpgsql_estate_setup(&estate, func, (ReturnSetInfo *) fcinfo->resultinfo,
     509              :                          simple_eval_estate, simple_eval_resowner);
     510        43242 :     estate.procedure_resowner = procedure_resowner;
     511        43242 :     estate.atomic = atomic;
     512              : 
     513              :     /*
     514              :      * Setup error traceback support for ereport()
     515              :      */
     516        43242 :     plerrcontext.callback = plpgsql_exec_error_callback;
     517        43242 :     plerrcontext.arg = &estate;
     518        43242 :     plerrcontext.previous = error_context_stack;
     519        43242 :     error_context_stack = &plerrcontext;
     520              : 
     521              :     /*
     522              :      * Make local execution copies of all the datums
     523              :      */
     524        43242 :     estate.err_text = gettext_noop("during initialization of execution state");
     525        43242 :     copy_plpgsql_datums(&estate, func);
     526              : 
     527              :     /*
     528              :      * Store the actual call argument values into the appropriate variables
     529              :      */
     530        43242 :     estate.err_text = gettext_noop("while storing call arguments into local variables");
     531        97657 :     for (i = 0; i < func->fn_nargs; i++)
     532              :     {
     533        54415 :         int         n = func->fn_argvarnos[i];
     534              : 
     535        54415 :         switch (estate.datums[n]->dtype)
     536              :         {
     537        53896 :             case PLPGSQL_DTYPE_VAR:
     538              :                 {
     539        53896 :                     PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[n];
     540              : 
     541        53896 :                     assign_simple_var(&estate, var,
     542              :                                       fcinfo->args[i].value,
     543        53896 :                                       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        53896 :                     if (!var->isnull && var->datatype->typlen == -1)
     563              :                     {
     564        23411 :                         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        23407 :                         else if (VARATT_IS_EXTERNAL_EXPANDED_RO(DatumGetPointer(var->value)))
     574              :                         {
     575              :                             /* R/O pointer, keep it as-is until assigned to */
     576              :                         }
     577        23363 :                         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        53896 :                 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        43242 :     estate.err_text = gettext_noop("during function entry");
     620              : 
     621              :     /*
     622              :      * Set the magic variable FOUND to false
     623              :      */
     624        43242 :     exec_set_found(&estate, false);
     625              : 
     626              :     /*
     627              :      * Let the instrumentation plugin peek at this function
     628              :      */
     629        43242 :     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        43242 :     estate.err_text = NULL;
     636        43242 :     rc = exec_toplevel_block(&estate, func->action);
     637        42699 :     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        42695 :     estate.err_text = gettext_noop("while casting return value to function's return type");
     649              : 
     650        42695 :     fcinfo->isnull = estate.retisnull;
     651              : 
     652        42695 :     if (estate.retisset)
     653              :     {
     654         2458 :         ReturnSetInfo *rsi = estate.rsi;
     655              : 
     656              :         /* Check caller can handle a set result */
     657         2458 :         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         2458 :         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         2458 :         rsi->returnMode = SFRM_Materialize;
     668              : 
     669              :         /* If we produced any tuples, send back the result */
     670         2458 :         if (estate.tuple_store)
     671              :         {
     672              :             MemoryContext oldcxt;
     673              : 
     674         2446 :             rsi->setResult = estate.tuple_store;
     675         2446 :             oldcxt = MemoryContextSwitchTo(estate.tuple_store_cxt);
     676         2446 :             rsi->setDesc = CreateTupleDescCopy(estate.tuple_store_desc);
     677         2446 :             MemoryContextSwitchTo(oldcxt);
     678              :         }
     679         2458 :         estate.retval = (Datum) 0;
     680         2458 :         fcinfo->isnull = true;
     681              :     }
     682        40237 :     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        39938 :         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        35617 :             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        35595 :             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        42652 :     estate.err_text = gettext_noop("during function exit");
     793              : 
     794              :     /*
     795              :      * Let the instrumentation plugin peek at this function
     796              :      */
     797        42652 :     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        42652 :     plpgsql_destroy_econtext(&estate);
     802        42652 :     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        42652 :     error_context_stack = plerrcontext.previous;
     809              : 
     810              :     /*
     811              :      * Return the function's result
     812              :      */
     813        42652 :     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        10274 : 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        10274 :     plpgsql_estate_setup(&estate, func, NULL, NULL, NULL);
     951        10274 :     estate.trigdata = trigdata;
     952              : 
     953              :     /*
     954              :      * Setup error traceback support for ereport()
     955              :      */
     956        10274 :     plerrcontext.callback = plpgsql_exec_error_callback;
     957        10274 :     plerrcontext.arg = &estate;
     958        10274 :     plerrcontext.previous = error_context_stack;
     959        10274 :     error_context_stack = &plerrcontext;
     960              : 
     961              :     /*
     962              :      * Make local execution copies of all the datums
     963              :      */
     964        10274 :     estate.err_text = gettext_noop("during initialization of execution state");
     965        10274 :     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        10274 :     tupdesc = RelationGetDescr(trigdata->tg_relation);
     978              : 
     979        10274 :     rec_new = (PLpgSQL_rec *) (estate.datums[func->new_varno]);
     980        10274 :     rec_old = (PLpgSQL_rec *) (estate.datums[func->old_varno]);
     981              : 
     982        10274 :     rec_new->erh = make_expanded_record_from_tupdesc(tupdesc,
     983              :                                                      estate.datum_context);
     984        10274 :     rec_old->erh = make_expanded_record_from_exprecord(rec_new->erh,
     985              :                                                        estate.datum_context);
     986              : 
     987        10274 :     if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
     988              :     {
     989              :         /*
     990              :          * Per-statement triggers don't use OLD/NEW variables
     991              :          */
     992              :     }
     993         9190 :     else if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
     994              :     {
     995         4739 :         expanded_record_set_tuple(rec_new->erh, trigdata->tg_trigtuple,
     996              :                                   false, false);
     997              :     }
     998         4451 :     else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
     999              :     {
    1000         4106 :         expanded_record_set_tuple(rec_new->erh, trigdata->tg_newtuple,
    1001              :                                   false, false);
    1002         4106 :         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         4106 :         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          345 :     else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
    1026              :     {
    1027          345 :         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        10274 :     rc = SPI_register_trigger_data(trigdata);
    1035              :     Assert(rc >= 0);
    1036              : 
    1037        10274 :     estate.err_text = gettext_noop("during function entry");
    1038              : 
    1039              :     /*
    1040              :      * Set the magic variable FOUND to false
    1041              :      */
    1042        10274 :     exec_set_found(&estate, false);
    1043              : 
    1044              :     /*
    1045              :      * Let the instrumentation plugin peek at this function
    1046              :      */
    1047        10274 :     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        10274 :     estate.err_text = NULL;
    1054        10274 :     rc = exec_toplevel_block(&estate, func->action);
    1055        10136 :     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        10136 :     estate.err_text = gettext_noop("during function exit");
    1064              : 
    1065        10136 :     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        10136 :     if (estate.retisnull || !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
    1081         1926 :         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         8210 :         if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(estate.retval)))
    1092              :         {
    1093         8208 :             ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(estate.retval);
    1094              : 
    1095              :             Assert(erh->er_magic == ER_MAGIC);
    1096              : 
    1097              :             /* Extract HeapTuple and TupleDesc */
    1098         8208 :             rettup = expanded_record_get_tuple(erh);
    1099              :             Assert(rettup);
    1100         8208 :             retdesc = expanded_record_get_tupdesc(erh);
    1101              : 
    1102         8208 :             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         8208 :             if (rettup != trigdata->tg_newtuple &&
    1121         5217 :                 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        10136 :     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        10136 :     plpgsql_destroy_econtext(&estate);
    1156        10136 :     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        10136 :     error_context_stack = plerrcontext.previous;
    1163              : 
    1164              :     /*
    1165              :      * Return the trigger's result
    1166              :      */
    1167        10136 :     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         1172 : 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         1172 :     plpgsql_estate_setup(&estate, func, NULL, NULL, NULL);
    1186         1172 :     estate.evtrigdata = trigdata;
    1187              : 
    1188              :     /*
    1189              :      * Setup error traceback support for ereport()
    1190              :      */
    1191         1172 :     plerrcontext.callback = plpgsql_exec_error_callback;
    1192         1172 :     plerrcontext.arg = &estate;
    1193         1172 :     plerrcontext.previous = error_context_stack;
    1194         1172 :     error_context_stack = &plerrcontext;
    1195              : 
    1196              :     /*
    1197              :      * Make local execution copies of all the datums
    1198              :      */
    1199         1172 :     estate.err_text = gettext_noop("during initialization of execution state");
    1200         1172 :     copy_plpgsql_datums(&estate, func);
    1201              : 
    1202              :     /*
    1203              :      * Let the instrumentation plugin peek at this function
    1204              :      */
    1205         1172 :     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         1172 :     estate.err_text = NULL;
    1212         1172 :     rc = exec_toplevel_block(&estate, func->action);
    1213         1156 :     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         1156 :     estate.err_text = gettext_noop("during function exit");
    1222              : 
    1223              :     /*
    1224              :      * Let the instrumentation plugin peek at this function
    1225              :      */
    1226         1156 :     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         1156 :     plpgsql_destroy_econtext(&estate);
    1231         1156 :     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         1156 :     error_context_stack = plerrcontext.previous;
    1238         1156 : }
    1239              : 
    1240              : /*
    1241              :  * error context callback to let us supply a call-stack traceback
    1242              :  */
    1243              : static void
    1244        16432 : plpgsql_exec_error_callback(void *arg)
    1245              : {
    1246        16432 :     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        16432 :     if (estate->err_var != NULL)
    1256           34 :         err_lineno = estate->err_var->lineno;
    1257        16398 :     else if (estate->err_stmt != NULL)
    1258        16351 :         err_lineno = estate->err_stmt->lineno;
    1259              :     else
    1260           47 :         err_lineno = 0;
    1261              : 
    1262        16432 :     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        16354 :     else if (estate->err_stmt != NULL && err_lineno > 0)
    1293              :     {
    1294              :         /* translator: last %s is a plpgsql statement type name */
    1295        16350 :         errcontext("PL/pgSQL function %s line %d at %s",
    1296        16350 :                    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        16432 : }
    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        54688 : copy_plpgsql_datums(PLpgSQL_execstate *estate,
    1343              :                     PLpgSQL_function *func)
    1344              : {
    1345        54688 :     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        54688 :     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        54688 :     workspace = palloc(func->copiable_size);
    1360        54688 :     ws_next = workspace;
    1361              : 
    1362              :     /* Fill datum-pointer array, copying datums into workspace as needed */
    1363        54688 :     indatums = func->datums;
    1364        54688 :     outdatums = estate->datums;
    1365       380678 :     for (i = 0; i < ndatums; i++)
    1366              :     {
    1367       325990 :         PLpgSQL_datum *indatum = indatums[i];
    1368              :         PLpgSQL_datum *outdatum;
    1369              : 
    1370              :         /* This must agree with plpgsql_finish_datums on what is copiable */
    1371       325990 :         switch (indatum->dtype)
    1372              :         {
    1373       260806 :             case PLPGSQL_DTYPE_VAR:
    1374              :             case PLPGSQL_DTYPE_PROMISE:
    1375       260806 :                 outdatum = (PLpgSQL_datum *) ws_next;
    1376       260806 :                 memcpy(outdatum, indatum, sizeof(PLpgSQL_var));
    1377       260806 :                 ws_next += MAXALIGN(sizeof(PLpgSQL_var));
    1378       260806 :                 break;
    1379              : 
    1380        24477 :             case PLPGSQL_DTYPE_REC:
    1381        24477 :                 outdatum = (PLpgSQL_datum *) ws_next;
    1382        24477 :                 memcpy(outdatum, indatum, sizeof(PLpgSQL_rec));
    1383        24477 :                 ws_next += MAXALIGN(sizeof(PLpgSQL_rec));
    1384        24477 :                 break;
    1385              : 
    1386        40707 :             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        40707 :                 outdatum = indatum;
    1395        40707 :                 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       325990 :         outdatums[i] = outdatum;
    1404              :     }
    1405              : 
    1406              :     Assert(ws_next == workspace + func->copiable_size);
    1407        54688 : }
    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        16647 : plpgsql_fulfill_promise(PLpgSQL_execstate *estate,
    1416              :                         PLpgSQL_var *var)
    1417              : {
    1418              :     MemoryContext oldcontext;
    1419              : 
    1420        16647 :     if (var->promise == PLPGSQL_PROMISE_NONE)
    1421         5066 :         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        11581 :     oldcontext = MemoryContextSwitchTo(estate->datum_context);
    1431              : 
    1432        11581 :     switch (var->promise)
    1433              :     {
    1434         1215 :         case PLPGSQL_PROMISE_TG_NAME:
    1435         1215 :             if (estate->trigdata == NULL)
    1436            0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1437         1215 :             assign_simple_var(estate, var,
    1438         1215 :                               DirectFunctionCall1(namein,
    1439              :                                                   CStringGetDatum(estate->trigdata->tg_trigger->tgname)),
    1440              :                               false, true);
    1441         1215 :             break;
    1442              : 
    1443         1843 :         case PLPGSQL_PROMISE_TG_WHEN:
    1444         1843 :             if (estate->trigdata == NULL)
    1445            0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1446         1843 :             if (TRIGGER_FIRED_BEFORE(estate->trigdata->tg_event))
    1447          762 :                 assign_text_var(estate, var, "BEFORE");
    1448         1081 :             else if (TRIGGER_FIRED_AFTER(estate->trigdata->tg_event))
    1449         1041 :                 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         1843 :             break;
    1455              : 
    1456         1727 :         case PLPGSQL_PROMISE_TG_LEVEL:
    1457         1727 :             if (estate->trigdata == NULL)
    1458            0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1459         1727 :             if (TRIGGER_FIRED_FOR_ROW(estate->trigdata->tg_event))
    1460         1067 :                 assign_text_var(estate, var, "ROW");
    1461          660 :             else if (TRIGGER_FIRED_FOR_STATEMENT(estate->trigdata->tg_event))
    1462          660 :                 assign_text_var(estate, var, "STATEMENT");
    1463              :             else
    1464            0 :                 elog(ERROR, "unrecognized trigger event type: not ROW or STATEMENT");
    1465         1727 :             break;
    1466              : 
    1467         4245 :         case PLPGSQL_PROMISE_TG_OP:
    1468         4245 :             if (estate->trigdata == NULL)
    1469            0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1470         4245 :             if (TRIGGER_FIRED_BY_INSERT(estate->trigdata->tg_event))
    1471         2085 :                 assign_text_var(estate, var, "INSERT");
    1472         2160 :             else if (TRIGGER_FIRED_BY_UPDATE(estate->trigdata->tg_event))
    1473         1842 :                 assign_text_var(estate, var, "UPDATE");
    1474          318 :             else if (TRIGGER_FIRED_BY_DELETE(estate->trigdata->tg_event))
    1475          308 :                 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         4245 :             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         1416 :         case PLPGSQL_PROMISE_TG_ARGV:
    1517         1416 :             if (estate->trigdata == NULL)
    1518            0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1519         1416 :             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         1404 :                 int         nelems = estate->trigdata->tg_trigger->tgnargs;
    1526              :                 Datum      *elems;
    1527              :                 int         dims[1];
    1528              :                 int         lbs[1];
    1529              :                 int         i;
    1530              : 
    1531         1404 :                 elems = palloc_array(Datum, nelems);
    1532         3116 :                 for (i = 0; i < nelems; i++)
    1533         1712 :                     elems[i] = CStringGetTextDatum(estate->trigdata->tg_trigger->tgargs[i]);
    1534         1404 :                 dims[0] = nelems;
    1535         1404 :                 lbs[0] = 0;
    1536              : 
    1537         1404 :                 assign_simple_var(estate, var,
    1538         1404 :                                   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         1416 :             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        11581 :     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        41943 : get_stmt_mcontext(PLpgSQL_execstate *estate)
    1576              : {
    1577        41943 :     if (estate->stmt_mcontext == NULL)
    1578              :     {
    1579        16306 :         estate->stmt_mcontext =
    1580        16306 :             AllocSetContextCreate(estate->stmt_mcontext_parent,
    1581              :                                   "PLpgSQL per-statement data",
    1582              :                                   ALLOCSET_DEFAULT_SIZES);
    1583              :     }
    1584        41943 :     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        54688 : exec_toplevel_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
    1666              : {
    1667              :     int         rc;
    1668              : 
    1669        54688 :     estate->err_stmt = (PLpgSQL_stmt *) block;
    1670              : 
    1671              :     /* Let the plugin know that we are about to execute this statement */
    1672        54688 :     if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
    1673            0 :         ((*plpgsql_plugin_ptr)->stmt_beg) (estate, (PLpgSQL_stmt *) block);
    1674              : 
    1675        54688 :     CHECK_FOR_INTERRUPTS();
    1676              : 
    1677        54688 :     rc = exec_stmt_block(estate, block);
    1678              : 
    1679              :     /* Let the plugin know that we have finished executing this statement */
    1680        53991 :     if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
    1681            0 :         ((*plpgsql_plugin_ptr)->stmt_end) (estate, (PLpgSQL_stmt *) block);
    1682              : 
    1683        53991 :     estate->err_stmt = NULL;
    1684              : 
    1685        53991 :     return rc;
    1686              : }
    1687              : 
    1688              : 
    1689              : /* ----------
    1690              :  * exec_stmt_block          Execute a block of statements
    1691              :  * ----------
    1692              :  */
    1693              : static int
    1694        63242 : exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
    1695              : {
    1696        63242 :     volatile int rc = -1;
    1697              :     int         i;
    1698              : 
    1699              :     /*
    1700              :      * First initialize all variables declared in this block
    1701              :      */
    1702        63242 :     estate->err_text = gettext_noop("during statement block local variable initialization");
    1703              : 
    1704        86273 :     for (i = 0; i < block->n_initvars; i++)
    1705              :     {
    1706        23065 :         int         n = block->initvarnos[i];
    1707        23065 :         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        23065 :         estate->err_var = (PLpgSQL_variable *) datum;
    1720              : 
    1721        23065 :         switch (datum->dtype)
    1722              :         {
    1723        19948 :             case PLPGSQL_DTYPE_VAR:
    1724              :                 {
    1725        19948 :                     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        19948 :                     assign_simple_var(estate, var, (Datum) 0, true, false);
    1732              : 
    1733        19948 :                     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        17540 :                         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         2408 :                         exec_assign_expr(estate, (PLpgSQL_datum *) var,
    1755              :                                          var->default_val);
    1756              :                     }
    1757              :                 }
    1758        19923 :                 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        63208 :     estate->err_var = NULL;
    1795              : 
    1796        63208 :     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        54505 :         estate->err_text = NULL;
    1985              : 
    1986        54505 :         rc = exec_stmts(estate, block->body);
    1987              :     }
    1988              : 
    1989        62504 :     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        62504 :     switch (rc)
    1997              :     {
    1998        62494 :         case PLPGSQL_RC_OK:
    1999              :         case PLPGSQL_RC_RETURN:
    2000              :         case PLPGSQL_RC_CONTINUE:
    2001        62494 :             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       204109 : exec_stmts(PLpgSQL_execstate *estate, List *stmts)
    2028              : {
    2029       204109 :     PLpgSQL_stmt *save_estmt = estate->err_stmt;
    2030              :     ListCell   *s;
    2031              : 
    2032       204109 :     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        53078 :         CHECK_FOR_INTERRUPTS();
    2040        53078 :         return PLPGSQL_RC_OK;
    2041              :     }
    2042              : 
    2043       379286 :     foreach(s, stmts)
    2044              :     {
    2045       295311 :         PLpgSQL_stmt *stmt = (PLpgSQL_stmt *) lfirst(s);
    2046              :         int         rc;
    2047              : 
    2048       295311 :         estate->err_stmt = stmt;
    2049              : 
    2050              :         /* Let the plugin know that we are about to execute this statement */
    2051       295311 :         if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
    2052            0 :             ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
    2053              : 
    2054       295311 :         CHECK_FOR_INTERRUPTS();
    2055              : 
    2056       295311 :         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        64044 :             case PLPGSQL_STMT_ASSIGN:
    2063        64044 :                 rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
    2064        63892 :                 break;
    2065              : 
    2066         3903 :             case PLPGSQL_STMT_PERFORM:
    2067         3903 :                 rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
    2068         2924 :                 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        72934 :             case PLPGSQL_STMT_IF:
    2079        72934 :                 rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
    2080        72805 :                 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         3052 :             case PLPGSQL_STMT_FORI:
    2095         3052 :                 rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
    2096         3037 :                 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         2096 :             case PLPGSQL_STMT_EXIT:
    2111         2096 :                 rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
    2112         2096 :                 break;
    2113              : 
    2114        54051 :             case PLPGSQL_STMT_RETURN:
    2115        54051 :                 rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
    2116        53987 :                 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         1827 :             case PLPGSQL_STMT_RETURN_QUERY:
    2123         1827 :                 rc = exec_stmt_return_query(estate, (PLpgSQL_stmt_return_query *) stmt);
    2124         1818 :                 break;
    2125              : 
    2126        13445 :             case PLPGSQL_STMT_RAISE:
    2127        13445 :                 rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
    2128        12795 :                 break;
    2129              : 
    2130         4476 :             case PLPGSQL_STMT_ASSERT:
    2131         4476 :                 rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
    2132         4460 :                 break;
    2133              : 
    2134        40522 :             case PLPGSQL_STMT_EXECSQL:
    2135        40522 :                 rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
    2136        37799 :                 break;
    2137              : 
    2138        11143 :             case PLPGSQL_STMT_DYNEXECUTE:
    2139        11143 :                 rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt);
    2140        10967 :                 break;
    2141              : 
    2142         6387 :             case PLPGSQL_STMT_DYNFORS:
    2143         6387 :                 rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
    2144         6383 :                 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       290271 :         if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
    2175            0 :             ((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
    2176              : 
    2177       290271 :         if (rc != PLPGSQL_RC_OK)
    2178              :         {
    2179        62016 :             estate->err_stmt = save_estmt;
    2180        62016 :             return rc;
    2181              :         }
    2182              :     }                           /* end of loop over statements */
    2183              : 
    2184        83975 :     estate->err_stmt = save_estmt;
    2185        83975 :     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        64044 : exec_stmt_assign(PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt)
    2196              : {
    2197              :     Assert(stmt->varno >= 0);
    2198              : 
    2199        64044 :     exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
    2200              : 
    2201        63892 :     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         3903 : exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
    2212              : {
    2213         3903 :     PLpgSQL_expr *expr = stmt->expr;
    2214              : 
    2215         3903 :     (void) exec_run_select(estate, expr, 0, NULL);
    2216         2924 :     exec_set_found(estate, (estate->eval_processed != 0));
    2217         2924 :     exec_eval_cleanup(estate);
    2218              : 
    2219         2924 :     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        72934 : exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
    2558              : {
    2559              :     bool        value;
    2560              :     bool        isnull;
    2561              :     ListCell   *lc;
    2562              : 
    2563        72934 :     value = exec_eval_boolean(estate, stmt->cond, &isnull);
    2564        72934 :     exec_eval_cleanup(estate);
    2565        72934 :     if (!isnull && value)
    2566        14610 :         return exec_stmts(estate, stmt->then_body);
    2567              : 
    2568        58513 :     foreach(lc, stmt->elsif_list)
    2569              :     {
    2570          707 :         PLpgSQL_if_elsif *elif = (PLpgSQL_if_elsif *) lfirst(lc);
    2571              : 
    2572          707 :         value = exec_eval_boolean(estate, elif->cond, &isnull);
    2573          707 :         exec_eval_cleanup(estate);
    2574          707 :         if (!isnull && value)
    2575          518 :             return exec_stmts(estate, elif->stmts);
    2576              :     }
    2577              : 
    2578        57806 :     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         3287 :         rc = exec_stmts(estate, stmt->body);
    2681              : 
    2682         3287 :         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         2099 :     {
    2702              :         bool        value;
    2703              :         bool        isnull;
    2704              : 
    2705         2383 :         value = exec_eval_boolean(estate, stmt->cond, &isnull);
    2706         2383 :         exec_eval_cleanup(estate);
    2707              : 
    2708         2383 :         if (isnull || !value)
    2709              :             break;
    2710              : 
    2711         2109 :         rc = exec_stmts(estate, stmt->body);
    2712              : 
    2713         2109 :         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         3052 : 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         3052 :     bool        found = false;
    2738         3052 :     int         rc = PLPGSQL_RC_OK;
    2739              : 
    2740         3052 :     var = (PLpgSQL_var *) (estate->datums[stmt->var->dno]);
    2741              : 
    2742              :     /*
    2743              :      * Get the value of the lower bound
    2744              :      */
    2745         3052 :     value = exec_eval_expr(estate, stmt->lower,
    2746              :                            &isnull, &valtype, &valtypmod);
    2747         3052 :     value = exec_cast_value(estate, value, &isnull,
    2748              :                             valtype, valtypmod,
    2749         3052 :                             var->datatype->typoid,
    2750         3052 :                             var->datatype->atttypmod);
    2751         3052 :     if (isnull)
    2752            0 :         ereport(ERROR,
    2753              :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    2754              :                  errmsg("lower bound of FOR loop cannot be null")));
    2755         3052 :     loop_value = DatumGetInt32(value);
    2756         3052 :     exec_eval_cleanup(estate);
    2757              : 
    2758              :     /*
    2759              :      * Get the value of the upper bound
    2760              :      */
    2761         3052 :     value = exec_eval_expr(estate, stmt->upper,
    2762              :                            &isnull, &valtype, &valtypmod);
    2763         3052 :     value = exec_cast_value(estate, value, &isnull,
    2764              :                             valtype, valtypmod,
    2765         3052 :                             var->datatype->typoid,
    2766         3052 :                             var->datatype->atttypmod);
    2767         3052 :     if (isnull)
    2768            0 :         ereport(ERROR,
    2769              :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    2770              :                  errmsg("upper bound of FOR loop cannot be null")));
    2771         3052 :     end_value = DatumGetInt32(value);
    2772         3052 :     exec_eval_cleanup(estate);
    2773              : 
    2774              :     /*
    2775              :      * Get the step value
    2776              :      */
    2777         3052 :     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         3043 :         step_value = 1;
    2798              : 
    2799              :     /*
    2800              :      * Now do the loop
    2801              :      */
    2802              :     for (;;)
    2803              :     {
    2804              :         /*
    2805              :          * Check against upper bound
    2806              :          */
    2807        21998 :         if (stmt->reverse)
    2808              :         {
    2809            8 :             if (loop_value < end_value)
    2810            1 :                 break;
    2811              :         }
    2812              :         else
    2813              :         {
    2814        21990 :             if (loop_value > end_value)
    2815         3023 :                 break;
    2816              :         }
    2817              : 
    2818        18974 :         found = true;           /* looped at least once */
    2819              : 
    2820              :         /*
    2821              :          * Assign current value to loop var
    2822              :          */
    2823        18974 :         assign_simple_var(estate, var, Int32GetDatum(loop_value), false, false);
    2824              : 
    2825              :         /*
    2826              :          * Execute the statements
    2827              :          */
    2828        18974 :         rc = exec_stmts(estate, stmt->body);
    2829              : 
    2830        18962 :         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        18951 :         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        18944 :             if (loop_value > (PG_INT32_MAX - step_value))
    2845            1 :                 break;
    2846        18943 :             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         3037 :     exec_set_found(estate, found);
    2857              : 
    2858         3037 :     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         2096 : exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
    3196              : {
    3197              :     /*
    3198              :      * If the exit / continue has a condition, evaluate it
    3199              :      */
    3200         2096 :     if (stmt->cond != NULL)
    3201              :     {
    3202              :         bool        value;
    3203              :         bool        isnull;
    3204              : 
    3205         1693 :         value = exec_eval_boolean(estate, stmt->cond, &isnull);
    3206         1693 :         exec_eval_cleanup(estate);
    3207         1693 :         if (isnull || value == false)
    3208         1596 :             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        54051 : 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        54051 :     if (estate->retisset)
    3236         2458 :         return PLPGSQL_RC_RETURN;
    3237              : 
    3238              :     /* initialize for null result */
    3239        51593 :     estate->retval = (Datum) 0;
    3240        51593 :     estate->retisnull = true;
    3241        51593 :     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        51593 :     if (stmt->retvarno >= 0)
    3256              :     {
    3257        36884 :         PLpgSQL_datum *retvar = estate->datums[stmt->retvarno];
    3258              : 
    3259        36884 :         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        12716 :             case PLPGSQL_DTYPE_ROW:
    3291              :             case PLPGSQL_DTYPE_REC:
    3292              :                 {
    3293              :                     /* exec_eval_datum can handle these cases */
    3294              :                     int32       rettypmod;
    3295              : 
    3296        12716 :                     exec_eval_datum(estate,
    3297              :                                     retvar,
    3298              :                                     &estate->rettype,
    3299              :                                     &rettypmod,
    3300              :                                     &estate->retval,
    3301              :                                     &estate->retisnull);
    3302              :                 }
    3303        12716 :                 break;
    3304              : 
    3305            0 :             default:
    3306            0 :                 elog(ERROR, "unrecognized dtype: %d", retvar->dtype);
    3307              :         }
    3308              : 
    3309        36880 :         return PLPGSQL_RC_RETURN;
    3310              :     }
    3311              : 
    3312        14709 :     if (stmt->expr != NULL)
    3313              :     {
    3314              :         int32       rettypmod;
    3315              : 
    3316        11359 :         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        11303 :         if (estate->retistuple && !estate->retisnull &&
    3326           71 :             !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        11299 :         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         3350 :     if (estate->fn_rettype == VOIDOID &&
    3340         3350 :         estate->func->fn_prokind != PROKIND_PROCEDURE)
    3341              :     {
    3342         3295 :         estate->retval = (Datum) 0;
    3343         3295 :         estate->retisnull = false;
    3344         3295 :         estate->rettype = VOIDOID;
    3345              :     }
    3346              : 
    3347         3350 :     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              :                     Form_pg_attribute attr;
    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         3300 :                     attr = TupleDescAttr(tupdesc, 0);
    3418         6600 :                     retval = exec_cast_value(estate,
    3419              :                                              retval,
    3420              :                                              &isNull,
    3421         3300 :                                              var->datatype->typoid,
    3422         3300 :                                              var->datatype->atttypmod,
    3423              :                                              attr->atttypid,
    3424              :                                              attr->atttypmod);
    3425              : 
    3426         3300 :                     tuplestore_putvalues(estate->tuple_store, tupdesc,
    3427              :                                          &retval, &isNull);
    3428              :                 }
    3429         3300 :                 break;
    3430              : 
    3431          136 :             case PLPGSQL_DTYPE_REC:
    3432              :                 {
    3433          136 :                     PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar;
    3434              :                     TupleDesc   rec_tupdesc;
    3435              :                     TupleConversionMap *tupmap;
    3436              : 
    3437              :                     /* If rec is null, try to convert it to a row of nulls */
    3438          136 :                     if (rec->erh == NULL)
    3439            2 :                         instantiate_empty_record_variable(estate, rec);
    3440          135 :                     if (ExpandedRecordIsEmpty(rec->erh))
    3441            1 :                         deconstruct_expanded_record(rec->erh);
    3442              : 
    3443              :                     /* Use eval_mcontext for tuple conversion work */
    3444          135 :                     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    3445          135 :                     rec_tupdesc = expanded_record_get_tupdesc(rec->erh);
    3446          135 :                     tupmap = convert_tuples_by_position(rec_tupdesc,
    3447              :                                                         tupdesc,
    3448              :                                                         gettext_noop("wrong record type supplied in RETURN NEXT"));
    3449          135 :                     tuple = expanded_record_get_tuple(rec->erh);
    3450          135 :                     if (tupmap)
    3451           29 :                         tuple = execute_attr_map_tuple(tuple, tupmap);
    3452          135 :                     tuplestore_puttuple(estate->tuple_store, tuple);
    3453          135 :                     MemoryContextSwitchTo(oldcontext);
    3454              :                 }
    3455          135 :                 break;
    3456              : 
    3457           96 :             case PLPGSQL_DTYPE_ROW:
    3458              :                 {
    3459           96 :                     PLpgSQL_row *row = (PLpgSQL_row *) retvar;
    3460              : 
    3461              :                     /* We get here if there are multiple OUT parameters */
    3462              : 
    3463              :                     /* Use eval_mcontext for tuple conversion work */
    3464           96 :                     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    3465           96 :                     tuple = make_tuple_from_row(estate, row, tupdesc);
    3466           96 :                     if (tuple == NULL)  /* should not happen */
    3467            0 :                         ereport(ERROR,
    3468              :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3469              :                                  errmsg("wrong record type supplied in RETURN NEXT")));
    3470           96 :                     tuplestore_puttuple(estate->tuple_store, tuple);
    3471           96 :                     MemoryContextSwitchTo(oldcontext);
    3472              :                 }
    3473           96 :                 break;
    3474              : 
    3475            0 :             default:
    3476            0 :                 elog(ERROR, "unrecognized dtype: %d", retvar->dtype);
    3477              :                 break;
    3478              :         }
    3479              :     }
    3480          363 :     else if (stmt->expr)
    3481              :     {
    3482              :         Datum       retval;
    3483              :         bool        isNull;
    3484              :         Oid         rettype;
    3485              :         int32       rettypmod;
    3486              : 
    3487          363 :         retval = exec_eval_expr(estate,
    3488              :                                 stmt->expr,
    3489              :                                 &isNull,
    3490              :                                 &rettype,
    3491              :                                 &rettypmod);
    3492              : 
    3493          363 :         if (estate->retistuple)
    3494              :         {
    3495              :             /* Expression should be of RECORD or composite type */
    3496          323 :             if (!isNull)
    3497              :             {
    3498              :                 HeapTupleData tmptup;
    3499              :                 TupleDesc   retvaldesc;
    3500              :                 TupleConversionMap *tupmap;
    3501              : 
    3502          319 :                 if (!type_is_rowtype(rettype))
    3503            0 :                     ereport(ERROR,
    3504              :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
    3505              :                              errmsg("cannot return non-composite value from function returning composite type")));
    3506              : 
    3507              :                 /* Use eval_mcontext for tuple conversion work */
    3508          319 :                 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    3509          319 :                 retvaldesc = deconstruct_composite_datum(retval, &tmptup);
    3510          319 :                 tuple = &tmptup;
    3511          319 :                 tupmap = convert_tuples_by_position(retvaldesc, tupdesc,
    3512              :                                                     gettext_noop("returned record type does not match expected record type"));
    3513          318 :                 if (tupmap)
    3514            1 :                     tuple = execute_attr_map_tuple(tuple, tupmap);
    3515          318 :                 tuplestore_puttuple(estate->tuple_store, tuple);
    3516          318 :                 ReleaseTupleDesc(retvaldesc);
    3517          318 :                 MemoryContextSwitchTo(oldcontext);
    3518              :             }
    3519              :             else
    3520              :             {
    3521              :                 /* Composite NULL --- store a row of nulls */
    3522              :                 Datum      *nulldatums;
    3523              :                 bool       *nullflags;
    3524              : 
    3525              :                 nulldatums = (Datum *)
    3526            4 :                     eval_mcontext_alloc0(estate, natts * sizeof(Datum));
    3527              :                 nullflags = (bool *)
    3528            4 :                     eval_mcontext_alloc(estate, natts * sizeof(bool));
    3529            4 :                 memset(nullflags, true, natts * sizeof(bool));
    3530            4 :                 tuplestore_putvalues(estate->tuple_store, tupdesc,
    3531              :                                      nulldatums, nullflags);
    3532              :             }
    3533              :         }
    3534              :         else
    3535              :         {
    3536              :             Form_pg_attribute attr;
    3537              : 
    3538              :             /* Simple scalar result */
    3539           40 :             if (natts != 1)
    3540            0 :                 ereport(ERROR,
    3541              :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    3542              :                          errmsg("wrong result type supplied in RETURN NEXT")));
    3543              : 
    3544              :             /* coerce type if needed */
    3545           40 :             attr = TupleDescAttr(tupdesc, 0);
    3546           40 :             retval = exec_cast_value(estate,
    3547              :                                      retval,
    3548              :                                      &isNull,
    3549              :                                      rettype,
    3550              :                                      rettypmod,
    3551              :                                      attr->atttypid,
    3552              :                                      attr->atttypmod);
    3553              : 
    3554           40 :             tuplestore_putvalues(estate->tuple_store, tupdesc,
    3555              :                                  &retval, &isNull);
    3556              :         }
    3557              :     }
    3558              :     else
    3559              :     {
    3560            0 :         ereport(ERROR,
    3561              :                 (errcode(ERRCODE_SYNTAX_ERROR),
    3562              :                  errmsg("RETURN NEXT must have a parameter")));
    3563              :     }
    3564              : 
    3565         3893 :     exec_eval_cleanup(estate);
    3566              : 
    3567         3893 :     return PLPGSQL_RC_OK;
    3568              : }
    3569              : 
    3570              : /* ----------
    3571              :  * exec_stmt_return_query       Evaluate a query and add it to the
    3572              :  *                              list of tuples returned by the current
    3573              :  *                              SRF.
    3574              :  * ----------
    3575              :  */
    3576              : static int
    3577         1827 : exec_stmt_return_query(PLpgSQL_execstate *estate,
    3578              :                        PLpgSQL_stmt_return_query *stmt)
    3579              : {
    3580              :     int64       tcount;
    3581              :     DestReceiver *treceiver;
    3582              :     int         rc;
    3583              :     uint64      processed;
    3584         1827 :     MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
    3585              :     MemoryContext oldcontext;
    3586              : 
    3587         1827 :     if (!estate->retisset)
    3588            0 :         ereport(ERROR,
    3589              :                 (errcode(ERRCODE_SYNTAX_ERROR),
    3590              :                  errmsg("cannot use RETURN QUERY in a non-SETOF function")));
    3591              : 
    3592         1827 :     if (estate->tuple_store == NULL)
    3593         1790 :         exec_init_tuple_store(estate);
    3594              :     /* There might be some tuples in the tuplestore already */
    3595         1827 :     tcount = tuplestore_tuple_count(estate->tuple_store);
    3596              : 
    3597              :     /*
    3598              :      * Set up DestReceiver to transfer results directly to tuplestore,
    3599              :      * converting rowtype if necessary.  DestReceiver lives in mcontext.
    3600              :      */
    3601         1827 :     oldcontext = MemoryContextSwitchTo(stmt_mcontext);
    3602         1827 :     treceiver = CreateDestReceiver(DestTuplestore);
    3603         1827 :     SetTuplestoreDestReceiverParams(treceiver,
    3604              :                                     estate->tuple_store,
    3605              :                                     estate->tuple_store_cxt,
    3606              :                                     false,
    3607              :                                     estate->tuple_store_desc,
    3608              :                                     gettext_noop("structure of query does not match function result type"));
    3609         1827 :     MemoryContextSwitchTo(oldcontext);
    3610              : 
    3611         1827 :     if (stmt->query != NULL)
    3612              :     {
    3613              :         /* static query */
    3614         1655 :         PLpgSQL_expr *expr = stmt->query;
    3615              :         ParamListInfo paramLI;
    3616              :         SPIExecuteOptions options;
    3617              : 
    3618              :         /*
    3619              :          * On the first call for this expression generate the plan.
    3620              :          */
    3621         1655 :         if (expr->plan == NULL)
    3622           47 :             exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK);
    3623              : 
    3624              :         /*
    3625              :          * Set up ParamListInfo to pass to executor
    3626              :          */
    3627         1655 :         paramLI = setup_param_list(estate, expr);
    3628              : 
    3629              :         /*
    3630              :          * Execute the query
    3631              :          */
    3632         1655 :         memset(&options, 0, sizeof(options));
    3633         1655 :         options.params = paramLI;
    3634         1655 :         options.read_only = estate->readonly_func;
    3635         1655 :         options.must_return_tuples = true;
    3636         1655 :         options.dest = treceiver;
    3637              : 
    3638         1655 :         rc = SPI_execute_plan_extended(expr->plan, &options);
    3639         1650 :         if (rc < 0)
    3640            0 :             elog(ERROR, "SPI_execute_plan_extended failed executing query \"%s\": %s",
    3641              :                  expr->query, SPI_result_code_string(rc));
    3642              :     }
    3643              :     else
    3644              :     {
    3645              :         /* RETURN QUERY EXECUTE */
    3646              :         Datum       query;
    3647              :         bool        isnull;
    3648              :         Oid         restype;
    3649              :         int32       restypmod;
    3650              :         char       *querystr;
    3651              :         SPIExecuteOptions options;
    3652              : 
    3653              :         /*
    3654              :          * Evaluate the string expression after the EXECUTE keyword. Its
    3655              :          * result is the querystring we have to execute.
    3656              :          */
    3657              :         Assert(stmt->dynquery != NULL);
    3658          172 :         query = exec_eval_expr(estate, stmt->dynquery,
    3659              :                                &isnull, &restype, &restypmod);
    3660          172 :         if (isnull)
    3661            0 :             ereport(ERROR,
    3662              :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    3663              :                      errmsg("query string argument of EXECUTE is null")));
    3664              : 
    3665              :         /* Get the C-String representation */
    3666          172 :         querystr = convert_value_to_string(estate, query, restype);
    3667              : 
    3668              :         /* copy it into the stmt_mcontext before we clean up */
    3669          172 :         querystr = MemoryContextStrdup(stmt_mcontext, querystr);
    3670              : 
    3671          172 :         exec_eval_cleanup(estate);
    3672              : 
    3673              :         /* Execute query, passing params if necessary */
    3674          172 :         memset(&options, 0, sizeof(options));
    3675          172 :         options.params = exec_eval_using_params(estate,
    3676              :                                                 stmt->params);
    3677          172 :         options.read_only = estate->readonly_func;
    3678          172 :         options.must_return_tuples = true;
    3679          172 :         options.dest = treceiver;
    3680              : 
    3681          172 :         rc = SPI_execute_extended(querystr, &options);
    3682          168 :         if (rc < 0)
    3683            0 :             elog(ERROR, "SPI_execute_extended failed executing query \"%s\": %s",
    3684              :                  querystr, SPI_result_code_string(rc));
    3685              :     }
    3686              : 
    3687              :     /* Clean up */
    3688         1818 :     treceiver->rDestroy(treceiver);
    3689         1818 :     exec_eval_cleanup(estate);
    3690         1818 :     MemoryContextReset(stmt_mcontext);
    3691              : 
    3692              :     /* Count how many tuples we got */
    3693         1818 :     processed = tuplestore_tuple_count(estate->tuple_store) - tcount;
    3694              : 
    3695         1818 :     estate->eval_processed = processed;
    3696         1818 :     exec_set_found(estate, processed != 0);
    3697              : 
    3698         1818 :     return PLPGSQL_RC_OK;
    3699              : }
    3700              : 
    3701              : static void
    3702         2457 : exec_init_tuple_store(PLpgSQL_execstate *estate)
    3703              : {
    3704         2457 :     ReturnSetInfo *rsi = estate->rsi;
    3705              :     MemoryContext oldcxt;
    3706              :     ResourceOwner oldowner;
    3707              : 
    3708              :     /*
    3709              :      * Check caller can handle a set result in the way we want
    3710              :      */
    3711         2457 :     if (!rsi || !IsA(rsi, ReturnSetInfo))
    3712            0 :         ereport(ERROR,
    3713              :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3714              :                  errmsg("set-valued function called in context that cannot accept a set")));
    3715              : 
    3716         2457 :     if (!(rsi->allowedModes & SFRM_Materialize) ||
    3717         2457 :         rsi->expectedDesc == NULL)
    3718            0 :         ereport(ERROR,
    3719              :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    3720              :                  errmsg("materialize mode required, but it is not allowed in this context")));
    3721              : 
    3722              :     /*
    3723              :      * Switch to the right memory context and resource owner for storing the
    3724              :      * tuplestore for return set. If we're within a subtransaction opened for
    3725              :      * an exception-block, for example, we must still create the tuplestore in
    3726              :      * the resource owner that was active when this function was entered, and
    3727              :      * not in the subtransaction resource owner.
    3728              :      */
    3729         2457 :     oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
    3730         2457 :     oldowner = CurrentResourceOwner;
    3731         2457 :     CurrentResourceOwner = estate->tuple_store_owner;
    3732              : 
    3733         2457 :     estate->tuple_store =
    3734         2457 :         tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
    3735              :                               false, work_mem);
    3736              : 
    3737         2457 :     CurrentResourceOwner = oldowner;
    3738         2457 :     MemoryContextSwitchTo(oldcxt);
    3739              : 
    3740         2457 :     estate->tuple_store_desc = rsi->expectedDesc;
    3741         2457 : }
    3742              : 
    3743              : #define SET_RAISE_OPTION_TEXT(opt, name) \
    3744              : do { \
    3745              :     if (opt) \
    3746              :         ereport(ERROR, \
    3747              :                 (errcode(ERRCODE_SYNTAX_ERROR), \
    3748              :                  errmsg("RAISE option already specified: %s", \
    3749              :                         name))); \
    3750              :     opt = MemoryContextStrdup(stmt_mcontext, extval); \
    3751              : } while (0)
    3752              : 
    3753              : /* ----------
    3754              :  * exec_stmt_raise          Build a message and throw it with elog()
    3755              :  * ----------
    3756              :  */
    3757              : static int
    3758        13445 : exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
    3759              : {
    3760        13445 :     int         err_code = 0;
    3761        13445 :     char       *condname = NULL;
    3762        13445 :     char       *err_message = NULL;
    3763        13445 :     char       *err_detail = NULL;
    3764        13445 :     char       *err_hint = NULL;
    3765        13445 :     char       *err_column = NULL;
    3766        13445 :     char       *err_constraint = NULL;
    3767        13445 :     char       *err_datatype = NULL;
    3768        13445 :     char       *err_table = NULL;
    3769        13445 :     char       *err_schema = NULL;
    3770              :     MemoryContext stmt_mcontext;
    3771              :     ListCell   *lc;
    3772              : 
    3773              :     /* RAISE with no parameters: re-throw current exception */
    3774        13445 :     if (stmt->condname == NULL && stmt->message == NULL &&
    3775           36 :         stmt->options == NIL)
    3776              :     {
    3777           24 :         if (estate->cur_error != NULL)
    3778           20 :             ReThrowError(estate->cur_error);
    3779              :         /* oops, we're not inside a handler */
    3780            4 :         ereport(ERROR,
    3781              :                 (errcode(ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER),
    3782              :                  errmsg("RAISE without parameters cannot be used outside an exception handler")));
    3783              :     }
    3784              : 
    3785              :     /* We'll need to accumulate the various strings in stmt_mcontext */
    3786        13421 :     stmt_mcontext = get_stmt_mcontext(estate);
    3787              : 
    3788        13421 :     if (stmt->condname)
    3789              :     {
    3790          438 :         err_code = plpgsql_recognize_err_condition(stmt->condname, true);
    3791          438 :         condname = MemoryContextStrdup(stmt_mcontext, stmt->condname);
    3792              :     }
    3793              : 
    3794        13421 :     if (stmt->message)
    3795              :     {
    3796              :         StringInfoData ds;
    3797              :         ListCell   *current_param;
    3798              :         char       *cp;
    3799              :         MemoryContext oldcontext;
    3800              : 
    3801              :         /* build string in stmt_mcontext */
    3802        12971 :         oldcontext = MemoryContextSwitchTo(stmt_mcontext);
    3803        12971 :         initStringInfo(&ds);
    3804        12971 :         MemoryContextSwitchTo(oldcontext);
    3805              : 
    3806        12971 :         current_param = list_head(stmt->params);
    3807              : 
    3808       222285 :         for (cp = stmt->message; *cp; cp++)
    3809              :         {
    3810              :             /*
    3811              :              * Occurrences of a single % are replaced by the next parameter's
    3812              :              * external representation. Double %'s are converted to one %.
    3813              :              */
    3814       209331 :             if (cp[0] == '%')
    3815              :             {
    3816              :                 Oid         paramtypeid;
    3817              :                 int32       paramtypmod;
    3818              :                 Datum       paramvalue;
    3819              :                 bool        paramisnull;
    3820              :                 char       *extval;
    3821              : 
    3822        31567 :                 if (cp[1] == '%')
    3823              :                 {
    3824            4 :                     appendStringInfoChar(&ds, '%');
    3825            4 :                     cp++;
    3826            4 :                     continue;
    3827              :                 }
    3828              : 
    3829              :                 /* should have been checked at compile time */
    3830        31563 :                 if (current_param == NULL)
    3831            0 :                     elog(ERROR, "unexpected RAISE parameter list length");
    3832              : 
    3833        31563 :                 paramvalue = exec_eval_expr(estate,
    3834        31563 :                                             (PLpgSQL_expr *) lfirst(current_param),
    3835              :                                             &paramisnull,
    3836              :                                             &paramtypeid,
    3837              :                                             &paramtypmod);
    3838              : 
    3839        31546 :                 if (paramisnull)
    3840          532 :                     extval = "<NULL>";
    3841              :                 else
    3842        31014 :                     extval = convert_value_to_string(estate,
    3843              :                                                      paramvalue,
    3844              :                                                      paramtypeid);
    3845        31546 :                 appendStringInfoString(&ds, extval);
    3846        31546 :                 current_param = lnext(stmt->params, current_param);
    3847        31546 :                 exec_eval_cleanup(estate);
    3848              :             }
    3849              :             else
    3850       177764 :                 appendStringInfoChar(&ds, cp[0]);
    3851              :         }
    3852              : 
    3853              :         /* should have been checked at compile time */
    3854        12954 :         if (current_param != NULL)
    3855            0 :             elog(ERROR, "unexpected RAISE parameter list length");
    3856              : 
    3857        12954 :         err_message = ds.data;
    3858              :     }
    3859              : 
    3860        13914 :     foreach(lc, stmt->options)
    3861              :     {
    3862          518 :         PLpgSQL_raise_option *opt = (PLpgSQL_raise_option *) lfirst(lc);
    3863              :         Datum       optionvalue;
    3864              :         bool        optionisnull;
    3865              :         Oid         optiontypeid;
    3866              :         int32       optiontypmod;
    3867              :         char       *extval;
    3868              : 
    3869          518 :         optionvalue = exec_eval_expr(estate, opt->expr,
    3870              :                                      &optionisnull,
    3871              :                                      &optiontypeid,
    3872              :                                      &optiontypmod);
    3873          518 :         if (optionisnull)
    3874            0 :             ereport(ERROR,
    3875              :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    3876              :                      errmsg("RAISE statement option cannot be null")));
    3877              : 
    3878          518 :         extval = convert_value_to_string(estate, optionvalue, optiontypeid);
    3879              : 
    3880          518 :         switch (opt->opt_type)
    3881              :         {
    3882           28 :             case PLPGSQL_RAISEOPTION_ERRCODE:
    3883           28 :                 if (err_code)
    3884            4 :                     ereport(ERROR,
    3885              :                             (errcode(ERRCODE_SYNTAX_ERROR),
    3886              :                              errmsg("RAISE option already specified: %s",
    3887              :                                     "ERRCODE")));
    3888           24 :                 err_code = plpgsql_recognize_err_condition(extval, true);
    3889           24 :                 condname = MemoryContextStrdup(stmt_mcontext, extval);
    3890           24 :                 break;
    3891          426 :             case PLPGSQL_RAISEOPTION_MESSAGE:
    3892          426 :                 SET_RAISE_OPTION_TEXT(err_message, "MESSAGE");
    3893          422 :                 break;
    3894           30 :             case PLPGSQL_RAISEOPTION_DETAIL:
    3895           30 :                 SET_RAISE_OPTION_TEXT(err_detail, "DETAIL");
    3896           30 :                 break;
    3897            9 :             case PLPGSQL_RAISEOPTION_HINT:
    3898            9 :                 SET_RAISE_OPTION_TEXT(err_hint, "HINT");
    3899            9 :                 break;
    3900            5 :             case PLPGSQL_RAISEOPTION_COLUMN:
    3901            5 :                 SET_RAISE_OPTION_TEXT(err_column, "COLUMN");
    3902            5 :                 break;
    3903            5 :             case PLPGSQL_RAISEOPTION_CONSTRAINT:
    3904            5 :                 SET_RAISE_OPTION_TEXT(err_constraint, "CONSTRAINT");
    3905            5 :                 break;
    3906            5 :             case PLPGSQL_RAISEOPTION_DATATYPE:
    3907            5 :                 SET_RAISE_OPTION_TEXT(err_datatype, "DATATYPE");
    3908            5 :                 break;
    3909            5 :             case PLPGSQL_RAISEOPTION_TABLE:
    3910            5 :                 SET_RAISE_OPTION_TEXT(err_table, "TABLE");
    3911            5 :                 break;
    3912            5 :             case PLPGSQL_RAISEOPTION_SCHEMA:
    3913            5 :                 SET_RAISE_OPTION_TEXT(err_schema, "SCHEMA");
    3914            5 :                 break;
    3915            0 :             default:
    3916            0 :                 elog(ERROR, "unrecognized raise option: %d", opt->opt_type);
    3917              :         }
    3918              : 
    3919          510 :         exec_eval_cleanup(estate);
    3920              :     }
    3921              : 
    3922              :     /* Default code if nothing specified */
    3923        13396 :     if (err_code == 0 && stmt->elog_level >= ERROR)
    3924          147 :         err_code = ERRCODE_RAISE_EXCEPTION;
    3925              : 
    3926              :     /* Default error message if nothing specified */
    3927        13396 :     if (err_message == NULL)
    3928              :     {
    3929           28 :         if (condname)
    3930              :         {
    3931           24 :             err_message = condname;
    3932           24 :             condname = NULL;
    3933              :         }
    3934              :         else
    3935            4 :             err_message = MemoryContextStrdup(stmt_mcontext,
    3936            4 :                                               unpack_sql_state(err_code));
    3937              :     }
    3938              : 
    3939              :     /*
    3940              :      * Throw the error (may or may not come back)
    3941              :      */
    3942        13396 :     ereport(stmt->elog_level,
    3943              :             (err_code ? errcode(err_code) : 0,
    3944              :              errmsg_internal("%s", err_message),
    3945              :              (err_detail != NULL) ? errdetail_internal("%s", err_detail) : 0,
    3946              :              (err_hint != NULL) ? errhint("%s", err_hint) : 0,
    3947              :              (err_column != NULL) ?
    3948              :              err_generic_string(PG_DIAG_COLUMN_NAME, err_column) : 0,
    3949              :              (err_constraint != NULL) ?
    3950              :              err_generic_string(PG_DIAG_CONSTRAINT_NAME, err_constraint) : 0,
    3951              :              (err_datatype != NULL) ?
    3952              :              err_generic_string(PG_DIAG_DATATYPE_NAME, err_datatype) : 0,
    3953              :              (err_table != NULL) ?
    3954              :              err_generic_string(PG_DIAG_TABLE_NAME, err_table) : 0,
    3955              :              (err_schema != NULL) ?
    3956              :              err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0));
    3957              : 
    3958              :     /* Clean up transient strings */
    3959        12795 :     MemoryContextReset(stmt_mcontext);
    3960              : 
    3961        12795 :     return PLPGSQL_RC_OK;
    3962              : }
    3963              : 
    3964              : /* ----------
    3965              :  * exec_stmt_assert         Assert statement
    3966              :  * ----------
    3967              :  */
    3968              : static int
    3969         4476 : exec_stmt_assert(PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
    3970              : {
    3971              :     bool        value;
    3972              :     bool        isnull;
    3973              : 
    3974              :     /* do nothing when asserts are not enabled */
    3975         4476 :     if (!plpgsql_check_asserts)
    3976            4 :         return PLPGSQL_RC_OK;
    3977              : 
    3978         4472 :     value = exec_eval_boolean(estate, stmt->cond, &isnull);
    3979         4472 :     exec_eval_cleanup(estate);
    3980              : 
    3981         4472 :     if (isnull || !value)
    3982              :     {
    3983           16 :         char       *message = NULL;
    3984              : 
    3985           16 :         if (stmt->message != NULL)
    3986              :         {
    3987              :             Datum       val;
    3988              :             Oid         typeid;
    3989              :             int32       typmod;
    3990              : 
    3991            8 :             val = exec_eval_expr(estate, stmt->message,
    3992              :                                  &isnull, &typeid, &typmod);
    3993            8 :             if (!isnull)
    3994            8 :                 message = convert_value_to_string(estate, val, typeid);
    3995              :             /* we mustn't do exec_eval_cleanup here */
    3996              :         }
    3997              : 
    3998           16 :         ereport(ERROR,
    3999              :                 (errcode(ERRCODE_ASSERT_FAILURE),
    4000              :                  message ? errmsg_internal("%s", message) :
    4001              :                  errmsg("assertion failed")));
    4002              :     }
    4003              : 
    4004         4456 :     return PLPGSQL_RC_OK;
    4005              : }
    4006              : 
    4007              : /* ----------
    4008              :  * Initialize a mostly empty execution state
    4009              :  * ----------
    4010              :  */
    4011              : static void
    4012        54688 : plpgsql_estate_setup(PLpgSQL_execstate *estate,
    4013              :                      PLpgSQL_function *func,
    4014              :                      ReturnSetInfo *rsi,
    4015              :                      EState *simple_eval_estate,
    4016              :                      ResourceOwner simple_eval_resowner)
    4017              : {
    4018              :     HASHCTL     ctl;
    4019              : 
    4020              :     /* this link will be restored at exit from plpgsql_call_handler */
    4021        54688 :     func->cur_estate = estate;
    4022              : 
    4023        54688 :     estate->func = func;
    4024        54688 :     estate->trigdata = NULL;
    4025        54688 :     estate->evtrigdata = NULL;
    4026              : 
    4027        54688 :     estate->retval = (Datum) 0;
    4028        54688 :     estate->retisnull = true;
    4029        54688 :     estate->rettype = InvalidOid;
    4030              : 
    4031        54688 :     estate->fn_rettype = func->fn_rettype;
    4032        54688 :     estate->retistuple = func->fn_retistuple;
    4033        54688 :     estate->retisset = func->fn_retset;
    4034              : 
    4035        54688 :     estate->readonly_func = func->fn_readonly;
    4036        54688 :     estate->atomic = true;
    4037              : 
    4038        54688 :     estate->exitlabel = NULL;
    4039        54688 :     estate->cur_error = NULL;
    4040              : 
    4041        54688 :     estate->tuple_store = NULL;
    4042        54688 :     estate->tuple_store_desc = NULL;
    4043        54688 :     if (rsi)
    4044              :     {
    4045         2672 :         estate->tuple_store_cxt = rsi->econtext->ecxt_per_query_memory;
    4046         2672 :         estate->tuple_store_owner = CurrentResourceOwner;
    4047              :     }
    4048              :     else
    4049              :     {
    4050        52016 :         estate->tuple_store_cxt = NULL;
    4051        52016 :         estate->tuple_store_owner = NULL;
    4052              :     }
    4053        54688 :     estate->rsi = rsi;
    4054              : 
    4055        54688 :     estate->found_varno = func->found_varno;
    4056        54688 :     estate->ndatums = func->ndatums;
    4057        54688 :     estate->datums = NULL;
    4058              :     /* the datums array will be filled by copy_plpgsql_datums() */
    4059        54688 :     estate->datum_context = CurrentMemoryContext;
    4060              : 
    4061              :     /* initialize our ParamListInfo with appropriate hook functions */
    4062        54688 :     estate->paramLI = makeParamList(0);
    4063        54688 :     estate->paramLI->paramFetch = plpgsql_param_fetch;
    4064        54688 :     estate->paramLI->paramFetchArg = estate;
    4065        54688 :     estate->paramLI->paramCompile = plpgsql_param_compile;
    4066        54688 :     estate->paramLI->paramCompileArg = NULL;  /* not needed */
    4067        54688 :     estate->paramLI->parserSetup = (ParserSetupHook) plpgsql_parser_setup;
    4068        54688 :     estate->paramLI->parserSetupArg = NULL; /* filled during use */
    4069        54688 :     estate->paramLI->numParams = estate->ndatums;
    4070              : 
    4071              :     /* Create the session-wide cast-expression hash if we didn't already */
    4072        54688 :     if (cast_expr_hash == NULL)
    4073              :     {
    4074          704 :         ctl.keysize = sizeof(plpgsql_CastHashKey);
    4075          704 :         ctl.entrysize = sizeof(plpgsql_CastExprHashEntry);
    4076          704 :         cast_expr_hash = hash_create("PLpgSQL cast expressions",
    4077              :                                      16,    /* start small and extend */
    4078              :                                      &ctl,
    4079              :                                      HASH_ELEM | HASH_BLOBS);
    4080              :     }
    4081              : 
    4082              :     /* set up for use of appropriate simple-expression EState and cast hash */
    4083        54688 :     if (simple_eval_estate)
    4084              :     {
    4085          816 :         estate->simple_eval_estate = simple_eval_estate;
    4086              :         /* Private cast hash just lives in function's main context */
    4087          816 :         ctl.keysize = sizeof(plpgsql_CastHashKey);
    4088          816 :         ctl.entrysize = sizeof(plpgsql_CastHashEntry);
    4089          816 :         ctl.hcxt = CurrentMemoryContext;
    4090          816 :         estate->cast_hash = hash_create("PLpgSQL private cast cache",
    4091              :                                         16, /* start small and extend */
    4092              :                                         &ctl,
    4093              :                                         HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
    4094              :     }
    4095              :     else
    4096              :     {
    4097        53872 :         estate->simple_eval_estate = shared_simple_eval_estate;
    4098              :         /* Create the session-wide cast-info hash table if we didn't already */
    4099        53872 :         if (shared_cast_hash == NULL)
    4100              :         {
    4101          593 :             ctl.keysize = sizeof(plpgsql_CastHashKey);
    4102          593 :             ctl.entrysize = sizeof(plpgsql_CastHashEntry);
    4103          593 :             shared_cast_hash = hash_create("PLpgSQL cast cache",
    4104              :                                            16,  /* start small and extend */
    4105              :                                            &ctl,
    4106              :                                            HASH_ELEM | HASH_BLOBS);
    4107              :         }
    4108        53872 :         estate->cast_hash = shared_cast_hash;
    4109              :     }
    4110              :     /* likewise for the simple-expression resource owner */
    4111        54688 :     if (simple_eval_resowner)
    4112          816 :         estate->simple_eval_resowner = simple_eval_resowner;
    4113              :     else
    4114        53872 :         estate->simple_eval_resowner = shared_simple_eval_resowner;
    4115              : 
    4116              :     /* if there's a procedure resowner, it'll be filled in later */
    4117        54688 :     estate->procedure_resowner = NULL;
    4118              : 
    4119              :     /*
    4120              :      * We start with no stmt_mcontext; one will be created only if needed.
    4121              :      * That context will be a direct child of the function's main execution
    4122              :      * context.  Additional stmt_mcontexts might be created as children of it.
    4123              :      */
    4124        54688 :     estate->stmt_mcontext = NULL;
    4125        54688 :     estate->stmt_mcontext_parent = CurrentMemoryContext;
    4126              : 
    4127        54688 :     estate->eval_tuptable = NULL;
    4128        54688 :     estate->eval_processed = 0;
    4129        54688 :     estate->eval_econtext = NULL;
    4130              : 
    4131        54688 :     estate->err_stmt = NULL;
    4132        54688 :     estate->err_var = NULL;
    4133        54688 :     estate->err_text = NULL;
    4134              : 
    4135        54688 :     estate->plugin_info = NULL;
    4136              : 
    4137              :     /*
    4138              :      * Create an EState and ExprContext for evaluation of simple expressions.
    4139              :      */
    4140        54688 :     plpgsql_create_econtext(estate);
    4141              : 
    4142              :     /*
    4143              :      * Let the plugin, if any, see this function before we initialize local
    4144              :      * PL/pgSQL variables.  Note that we also give the plugin a few function
    4145              :      * pointers, so it can call back into PL/pgSQL for doing things like
    4146              :      * variable assignments and stack traces.
    4147              :      */
    4148        54688 :     if (*plpgsql_plugin_ptr)
    4149              :     {
    4150            0 :         (*plpgsql_plugin_ptr)->error_callback = plpgsql_exec_error_callback;
    4151            0 :         (*plpgsql_plugin_ptr)->assign_expr = exec_assign_expr;
    4152            0 :         (*plpgsql_plugin_ptr)->assign_value = exec_assign_value;
    4153            0 :         (*plpgsql_plugin_ptr)->eval_datum = exec_eval_datum;
    4154            0 :         (*plpgsql_plugin_ptr)->cast_value = exec_cast_value;
    4155              : 
    4156            0 :         if ((*plpgsql_plugin_ptr)->func_setup)
    4157            0 :             ((*plpgsql_plugin_ptr)->func_setup) (estate, func);
    4158              :     }
    4159        54688 : }
    4160              : 
    4161              : /* ----------
    4162              :  * Release temporary memory used by expression/subselect evaluation
    4163              :  *
    4164              :  * NB: the result of the evaluation is no longer valid after this is done,
    4165              :  * unless it is a pass-by-value datatype.
    4166              :  * ----------
    4167              :  */
    4168              : static void
    4169       324392 : exec_eval_cleanup(PLpgSQL_execstate *estate)
    4170              : {
    4171              :     /* Clear result of a full SPI_execute */
    4172       324392 :     if (estate->eval_tuptable != NULL)
    4173         8212 :         SPI_freetuptable(estate->eval_tuptable);
    4174       324392 :     estate->eval_tuptable = NULL;
    4175              : 
    4176              :     /*
    4177              :      * Clear result of exec_eval_simple_expr (but keep the econtext).  This
    4178              :      * also clears any short-lived allocations done via get_eval_mcontext.
    4179              :      */
    4180       324392 :     if (estate->eval_econtext != NULL)
    4181       270448 :         ResetExprContext(estate->eval_econtext);
    4182       324392 : }
    4183              : 
    4184              : 
    4185              : /* ----------
    4186              :  * Generate a prepared plan
    4187              :  *
    4188              :  * CAUTION: it is possible for this function to throw an error after it has
    4189              :  * built a SPIPlan and saved it in expr->plan.  Therefore, be wary of doing
    4190              :  * additional things contingent on expr->plan being NULL.  That is, given
    4191              :  * code like
    4192              :  *
    4193              :  *  if (query->plan == NULL)
    4194              :  *  {
    4195              :  *      // okay to put setup code here
    4196              :  *      exec_prepare_plan(estate, query, ...);
    4197              :  *      // NOT okay to put more logic here
    4198              :  *  }
    4199              :  *
    4200              :  * extra steps at the end are unsafe because they will not be executed when
    4201              :  * re-executing the calling statement, if exec_prepare_plan failed the first
    4202              :  * time.  This is annoyingly error-prone, but the alternatives are worse.
    4203              :  * ----------
    4204              :  */
    4205              : static void
    4206        17888 : exec_prepare_plan(PLpgSQL_execstate *estate,
    4207              :                   PLpgSQL_expr *expr, int cursorOptions)
    4208              : {
    4209              :     SPIPlanPtr  plan;
    4210              :     SPIPrepareOptions options;
    4211              : 
    4212              :     /*
    4213              :      * Generate and save the plan
    4214              :      */
    4215        17888 :     memset(&options, 0, sizeof(options));
    4216        17888 :     options.parserSetup = (ParserSetupHook) plpgsql_parser_setup;
    4217        17888 :     options.parserSetupArg = expr;
    4218        17888 :     options.parseMode = expr->parseMode;
    4219        17888 :     options.cursorOptions = cursorOptions;
    4220        17888 :     plan = SPI_prepare_extended(expr->query, &options);
    4221        17827 :     if (plan == NULL)
    4222            0 :         elog(ERROR, "SPI_prepare_extended failed for \"%s\": %s",
    4223              :              expr->query, SPI_result_code_string(SPI_result));
    4224              : 
    4225        17827 :     SPI_keepplan(plan);
    4226        17827 :     expr->plan = plan;
    4227              : 
    4228              :     /* Check to see if it's a simple expression */
    4229        17827 :     exec_simple_check_plan(estate, expr);
    4230        17802 : }
    4231              : 
    4232              : 
    4233              : /* ----------
    4234              :  * exec_stmt_execsql            Execute an SQL statement (possibly with INTO).
    4235              :  *
    4236              :  * Note: some callers rely on this not touching stmt_mcontext.  If it ever
    4237              :  * needs to use that, fix those callers to push/pop stmt_mcontext.
    4238              :  * ----------
    4239              :  */
    4240              : static int
    4241        40562 : exec_stmt_execsql(PLpgSQL_execstate *estate,
    4242              :                   PLpgSQL_stmt_execsql *stmt)
    4243              : {
    4244              :     ParamListInfo paramLI;
    4245              :     long        tcount;
    4246              :     int         rc;
    4247        40562 :     PLpgSQL_expr *expr = stmt->sqlstmt;
    4248        40562 :     int         too_many_rows_level = 0;
    4249              : 
    4250        40562 :     if (plpgsql_extra_errors & PLPGSQL_XCHECK_TOOMANYROWS)
    4251            4 :         too_many_rows_level = ERROR;
    4252        40558 :     else if (plpgsql_extra_warnings & PLPGSQL_XCHECK_TOOMANYROWS)
    4253            4 :         too_many_rows_level = WARNING;
    4254              : 
    4255              :     /*
    4256              :      * On the first call for this statement generate the plan, and detect
    4257              :      * whether the statement is INSERT/UPDATE/DELETE/MERGE
    4258              :      */
    4259        40562 :     if (expr->plan == NULL)
    4260         1697 :         exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK);
    4261              : 
    4262        40548 :     if (!stmt->mod_stmt_set)
    4263              :     {
    4264              :         ListCell   *l;
    4265              : 
    4266         1693 :         stmt->mod_stmt = false;
    4267         2843 :         foreach(l, SPI_plan_get_plan_sources(expr->plan))
    4268              :         {
    4269         1693 :             CachedPlanSource *plansource = (CachedPlanSource *) lfirst(l);
    4270              : 
    4271              :             /*
    4272              :              * We could look at the raw_parse_tree, but it seems simpler to
    4273              :              * check the command tag.  Note we should *not* look at the Query
    4274              :              * tree(s), since those are the result of rewriting and could be
    4275              :              * stale, or could have been transmogrified into something else
    4276              :              * entirely.
    4277              :              */
    4278         1693 :             if (plansource->commandTag == CMDTAG_INSERT ||
    4279         1382 :                 plansource->commandTag == CMDTAG_UPDATE ||
    4280         1244 :                 plansource->commandTag == CMDTAG_DELETE ||
    4281         1186 :                 plansource->commandTag == CMDTAG_MERGE)
    4282              :             {
    4283          543 :                 stmt->mod_stmt = true;
    4284          543 :                 break;
    4285              :             }
    4286              :         }
    4287         1693 :         stmt->mod_stmt_set = true;
    4288              :     }
    4289              : 
    4290              :     /*
    4291              :      * Some users write "SELECT expr INTO var" instead of "var := expr".  If
    4292              :      * the expression is simple and the INTO target is a single variable, we
    4293              :      * can bypass SPI and call ExecEvalExpr() directly.  (exec_eval_expr would
    4294              :      * actually work for non-simple expressions too, but such an expression
    4295              :      * might return more or less than one row, complicating matters greatly.
    4296              :      * The potential performance win is small if it's non-simple, and any
    4297              :      * errors we might issue would likely look different, so avoid using this
    4298              :      * code path for non-simple cases.)
    4299              :      */
    4300        40548 :     if (expr->expr_simple_expr && stmt->into)
    4301              :     {
    4302         1303 :         PLpgSQL_datum *target = estate->datums[stmt->target->dno];
    4303              : 
    4304         1303 :         if (target->dtype == PLPGSQL_DTYPE_ROW)
    4305              :         {
    4306         1298 :             PLpgSQL_row *row = (PLpgSQL_row *) target;
    4307              : 
    4308         1298 :             if (row->nfields == 1)
    4309              :             {
    4310              :                 ErrorContextCallback plerrcontext;
    4311              :                 Datum       value;
    4312              :                 bool        isnull;
    4313              :                 Oid         valtype;
    4314              :                 int32       valtypmod;
    4315              : 
    4316              :                 /*
    4317              :                  * Setup error traceback support for ereport().  This is so
    4318              :                  * that error reports for the expression will look similar
    4319              :                  * whether or not we take this code path.
    4320              :                  */
    4321         1290 :                 plerrcontext.callback = plpgsql_execsql_error_callback;
    4322         1290 :                 plerrcontext.arg = expr;
    4323         1290 :                 plerrcontext.previous = error_context_stack;
    4324         1290 :                 error_context_stack = &plerrcontext;
    4325              : 
    4326              :                 /* If first time through, create a plan for this expression */
    4327         1290 :                 if (expr->plan == NULL)
    4328            0 :                     exec_prepare_plan(estate, expr, 0);
    4329              : 
    4330              :                 /* And evaluate the expression */
    4331         1290 :                 value = exec_eval_expr(estate, expr,
    4332              :                                        &isnull, &valtype, &valtypmod);
    4333              : 
    4334              :                 /*
    4335              :                  * Pop the error context stack: the code below would not use
    4336              :                  * SPI's error handling during the assignment step.
    4337              :                  */
    4338         1286 :                 error_context_stack = plerrcontext.previous;
    4339              : 
    4340              :                 /* Assign the result to the INTO target */
    4341         1286 :                 exec_assign_value(estate, estate->datums[row->varnos[0]],
    4342              :                                   value, isnull, valtype, valtypmod);
    4343         1285 :                 exec_eval_cleanup(estate);
    4344              : 
    4345              :                 /*
    4346              :                  * We must duplicate the other effects of the code below, as
    4347              :                  * well.  We know that exactly one row was returned, so it
    4348              :                  * doesn't matter whether the INTO was STRICT or not.
    4349              :                  */
    4350         1285 :                 exec_set_found(estate, true);
    4351         1285 :                 estate->eval_processed = 1;
    4352              : 
    4353         1285 :                 return PLPGSQL_RC_OK;
    4354              :             }
    4355              :         }
    4356              :     }
    4357              : 
    4358              :     /*
    4359              :      * Set up ParamListInfo to pass to executor
    4360              :      */
    4361        39258 :     paramLI = setup_param_list(estate, expr);
    4362              : 
    4363              :     /*
    4364              :      * If we have INTO, then we only need one row back ... but if we have INTO
    4365              :      * STRICT or extra check too_many_rows, ask for two rows, so that we can
    4366              :      * verify the statement returns only one.  INSERT/UPDATE/DELETE/MERGE are
    4367              :      * always treated strictly. Without INTO, just run the statement to
    4368              :      * completion (tcount = 0).
    4369              :      *
    4370              :      * We could just ask for two rows always when using INTO, but there are
    4371              :      * some cases where demanding the extra row costs significant time, eg by
    4372              :      * forcing completion of a sequential scan.  So don't do it unless we need
    4373              :      * to enforce strictness.
    4374              :      */
    4375        39258 :     if (stmt->into)
    4376              :     {
    4377        10106 :         if (stmt->strict || stmt->mod_stmt || too_many_rows_level)
    4378         1229 :             tcount = 2;
    4379              :         else
    4380         8877 :             tcount = 1;
    4381              :     }
    4382              :     else
    4383        29152 :         tcount = 0;
    4384              : 
    4385              :     /*
    4386              :      * Execute the plan
    4387              :      */
    4388        39258 :     rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
    4389        39258 :                                          estate->readonly_func, tcount);
    4390              : 
    4391              :     /*
    4392              :      * Check for error, and set FOUND if appropriate (for historical reasons
    4393              :      * we set FOUND only for certain query types).  Also Assert that we
    4394              :      * identified the statement type the same as SPI did.
    4395              :      */
    4396        36609 :     switch (rc)
    4397              :     {
    4398         6418 :         case SPI_OK_SELECT:
    4399              :             Assert(!stmt->mod_stmt);
    4400         6418 :             exec_set_found(estate, (SPI_processed != 0));
    4401         6418 :             break;
    4402              : 
    4403        18088 :         case SPI_OK_INSERT:
    4404              :         case SPI_OK_UPDATE:
    4405              :         case SPI_OK_DELETE:
    4406              :         case SPI_OK_MERGE:
    4407              :         case SPI_OK_INSERT_RETURNING:
    4408              :         case SPI_OK_UPDATE_RETURNING:
    4409              :         case SPI_OK_DELETE_RETURNING:
    4410              :         case SPI_OK_MERGE_RETURNING:
    4411              :             Assert(stmt->mod_stmt);
    4412        18088 :             exec_set_found(estate, (SPI_processed != 0));
    4413        18088 :             break;
    4414              : 
    4415        12100 :         case SPI_OK_SELINTO:
    4416              :         case SPI_OK_UTILITY:
    4417              :             Assert(!stmt->mod_stmt);
    4418        12100 :             break;
    4419              : 
    4420            0 :         case SPI_OK_REWRITTEN:
    4421              : 
    4422              :             /*
    4423              :              * The command was rewritten into another kind of command. It's
    4424              :              * not clear what FOUND would mean in that case (and SPI doesn't
    4425              :              * return the row count either), so just set it to false.  Note
    4426              :              * that we can't assert anything about mod_stmt here.
    4427              :              */
    4428            0 :             exec_set_found(estate, false);
    4429            0 :             break;
    4430              : 
    4431              :             /* Some SPI errors deserve specific error messages */
    4432            2 :         case SPI_ERROR_COPY:
    4433            2 :             ereport(ERROR,
    4434              :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4435              :                      errmsg("cannot COPY to/from client in PL/pgSQL")));
    4436              :             break;
    4437              : 
    4438            1 :         case SPI_ERROR_TRANSACTION:
    4439            1 :             ereport(ERROR,
    4440              :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4441              :                      errmsg("unsupported transaction command in PL/pgSQL")));
    4442              :             break;
    4443              : 
    4444            0 :         default:
    4445            0 :             elog(ERROR, "SPI_execute_plan_with_paramlist failed executing query \"%s\": %s",
    4446              :                  expr->query, SPI_result_code_string(rc));
    4447              :             break;
    4448              :     }
    4449              : 
    4450              :     /* All variants should save result info for GET DIAGNOSTICS */
    4451        36606 :     estate->eval_processed = SPI_processed;
    4452              : 
    4453              :     /* Process INTO if present */
    4454        36606 :     if (stmt->into)
    4455              :     {
    4456         7496 :         SPITupleTable *tuptab = SPI_tuptable;
    4457         7496 :         uint64      n = SPI_processed;
    4458              :         PLpgSQL_variable *target;
    4459              : 
    4460              :         /* If the statement did not return a tuple table, complain */
    4461         7496 :         if (tuptab == NULL)
    4462            0 :             ereport(ERROR,
    4463              :                     (errcode(ERRCODE_SYNTAX_ERROR),
    4464              :                      errmsg("INTO used with a command that cannot return data")));
    4465              : 
    4466              :         /* Fetch target's datum entry */
    4467         7496 :         target = (PLpgSQL_variable *) estate->datums[stmt->target->dno];
    4468              : 
    4469              :         /*
    4470              :          * If SELECT ... INTO specified STRICT, and the query didn't find
    4471              :          * exactly one row, throw an error.  If STRICT was not specified, then
    4472              :          * allow the query to find any number of rows.
    4473              :          */
    4474         7496 :         if (n == 0)
    4475              :         {
    4476           41 :             if (stmt->strict)
    4477              :             {
    4478              :                 char       *errdetail;
    4479              : 
    4480           12 :                 if (estate->func->print_strict_params)
    4481            8 :                     errdetail = format_expr_params(estate, expr);
    4482              :                 else
    4483            4 :                     errdetail = NULL;
    4484              : 
    4485           12 :                 ereport(ERROR,
    4486              :                         (errcode(ERRCODE_NO_DATA_FOUND),
    4487              :                          errmsg("query returned no rows"),
    4488              :                          errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
    4489              :             }
    4490              :             /* set the target to NULL(s) */
    4491           29 :             exec_move_row(estate, target, NULL, tuptab->tupdesc);
    4492              :         }
    4493              :         else
    4494              :         {
    4495         7455 :             if (n > 1 && (stmt->strict || stmt->mod_stmt || too_many_rows_level))
    4496              :             {
    4497              :                 char       *errdetail;
    4498              :                 int         errlevel;
    4499              : 
    4500           32 :                 if (estate->func->print_strict_params)
    4501           12 :                     errdetail = format_expr_params(estate, expr);
    4502              :                 else
    4503           20 :                     errdetail = NULL;
    4504              : 
    4505           32 :                 errlevel = (stmt->strict || stmt->mod_stmt) ? ERROR : too_many_rows_level;
    4506              : 
    4507           32 :                 ereport(errlevel,
    4508              :                         (errcode(ERRCODE_TOO_MANY_ROWS),
    4509              :                          errmsg("query returned more than one row"),
    4510              :                          errdetail ? errdetail_internal("parameters: %s", errdetail) : 0,
    4511              :                          errhint("Make sure the query returns a single row, or use LIMIT 1.")));
    4512              :             }
    4513              :             /* Put the first result row into the target */
    4514         7427 :             exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc);
    4515              :         }
    4516              : 
    4517              :         /* Clean up */
    4518         7440 :         exec_eval_cleanup(estate);
    4519         7440 :         SPI_freetuptable(SPI_tuptable);
    4520              :     }
    4521              :     else
    4522              :     {
    4523              :         /* If the statement returned a tuple table, complain */
    4524        29110 :         if (SPI_tuptable != NULL)
    4525            0 :             ereport(ERROR,
    4526              :                     (errcode(ERRCODE_SYNTAX_ERROR),
    4527              :                      errmsg("query has no destination for result data"),
    4528              :                      (rc == SPI_OK_SELECT) ? errhint("If you want to discard the results of a SELECT, use PERFORM instead.") : 0));
    4529              :     }
    4530              : 
    4531        36550 :     return PLPGSQL_RC_OK;
    4532              : }
    4533              : 
    4534              : 
    4535              : /* ----------
    4536              :  * exec_stmt_dynexecute         Execute a dynamic SQL query
    4537              :  *                  (possibly with INTO).
    4538              :  * ----------
    4539              :  */
    4540              : static int
    4541        11143 : exec_stmt_dynexecute(PLpgSQL_execstate *estate,
    4542              :                      PLpgSQL_stmt_dynexecute *stmt)
    4543              : {
    4544              :     Datum       query;
    4545              :     bool        isnull;
    4546              :     Oid         restype;
    4547              :     int32       restypmod;
    4548              :     char       *querystr;
    4549              :     int         exec_res;
    4550              :     ParamListInfo paramLI;
    4551              :     SPIExecuteOptions options;
    4552        11143 :     MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
    4553              : 
    4554              :     /*
    4555              :      * First we evaluate the string expression after the EXECUTE keyword. Its
    4556              :      * result is the querystring we have to execute.
    4557              :      */
    4558        11143 :     query = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod);
    4559        11143 :     if (isnull)
    4560            0 :         ereport(ERROR,
    4561              :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    4562              :                  errmsg("query string argument of EXECUTE is null")));
    4563              : 
    4564              :     /* Get the C-String representation */
    4565        11143 :     querystr = convert_value_to_string(estate, query, restype);
    4566              : 
    4567              :     /* copy it into the stmt_mcontext before we clean up */
    4568        11143 :     querystr = MemoryContextStrdup(stmt_mcontext, querystr);
    4569              : 
    4570        11143 :     exec_eval_cleanup(estate);
    4571              : 
    4572              :     /*
    4573              :      * Execute the query without preparing a saved plan.
    4574              :      */
    4575        11143 :     paramLI = exec_eval_using_params(estate, stmt->params);
    4576              : 
    4577        11143 :     memset(&options, 0, sizeof(options));
    4578        11143 :     options.params = paramLI;
    4579        11143 :     options.read_only = estate->readonly_func;
    4580              : 
    4581        11143 :     exec_res = SPI_execute_extended(querystr, &options);
    4582              : 
    4583        10990 :     switch (exec_res)
    4584              :     {
    4585        10987 :         case SPI_OK_SELECT:
    4586              :         case SPI_OK_INSERT:
    4587              :         case SPI_OK_UPDATE:
    4588              :         case SPI_OK_DELETE:
    4589              :         case SPI_OK_MERGE:
    4590              :         case SPI_OK_INSERT_RETURNING:
    4591              :         case SPI_OK_UPDATE_RETURNING:
    4592              :         case SPI_OK_DELETE_RETURNING:
    4593              :         case SPI_OK_MERGE_RETURNING:
    4594              :         case SPI_OK_UTILITY:
    4595              :         case SPI_OK_REWRITTEN:
    4596        10987 :             break;
    4597              : 
    4598            0 :         case 0:
    4599              : 
    4600              :             /*
    4601              :              * Also allow a zero return, which implies the querystring
    4602              :              * contained no commands.
    4603              :              */
    4604            0 :             break;
    4605              : 
    4606            0 :         case SPI_OK_SELINTO:
    4607              : 
    4608              :             /*
    4609              :              * We want to disallow SELECT INTO for now, because its behavior
    4610              :              * is not consistent with SELECT INTO in a normal plpgsql context.
    4611              :              * (We need to reimplement EXECUTE to parse the string as a
    4612              :              * plpgsql command, not just feed it to SPI_execute.)  This is not
    4613              :              * a functional limitation because CREATE TABLE AS is allowed.
    4614              :              */
    4615            0 :             ereport(ERROR,
    4616              :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4617              :                      errmsg("EXECUTE of SELECT ... INTO is not implemented"),
    4618              :                      errhint("You might want to use EXECUTE ... INTO or EXECUTE CREATE TABLE ... AS instead.")));
    4619              :             break;
    4620              : 
    4621              :             /* Some SPI errors deserve specific error messages */
    4622            2 :         case SPI_ERROR_COPY:
    4623            2 :             ereport(ERROR,
    4624              :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4625              :                      errmsg("cannot COPY to/from client in PL/pgSQL")));
    4626              :             break;
    4627              : 
    4628            1 :         case SPI_ERROR_TRANSACTION:
    4629            1 :             ereport(ERROR,
    4630              :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    4631              :                      errmsg("EXECUTE of transaction commands is not implemented")));
    4632              :             break;
    4633              : 
    4634            0 :         default:
    4635            0 :             elog(ERROR, "SPI_execute_extended failed executing query \"%s\": %s",
    4636              :                  querystr, SPI_result_code_string(exec_res));
    4637              :             break;
    4638              :     }
    4639              : 
    4640              :     /* Save result info for GET DIAGNOSTICS */
    4641        10987 :     estate->eval_processed = SPI_processed;
    4642              : 
    4643              :     /* Process INTO if present */
    4644        10987 :     if (stmt->into)
    4645              :     {
    4646         3944 :         SPITupleTable *tuptab = SPI_tuptable;
    4647         3944 :         uint64      n = SPI_processed;
    4648              :         PLpgSQL_variable *target;
    4649              : 
    4650              :         /* If the statement did not return a tuple table, complain */
    4651         3944 :         if (tuptab == NULL)
    4652            0 :             ereport(ERROR,
    4653              :                     (errcode(ERRCODE_SYNTAX_ERROR),
    4654              :                      errmsg("INTO used with a command that cannot return data")));
    4655              : 
    4656              :         /* Fetch target's datum entry */
    4657         3944 :         target = (PLpgSQL_variable *) estate->datums[stmt->target->dno];
    4658              : 
    4659              :         /*
    4660              :          * If SELECT ... INTO specified STRICT, and the query didn't find
    4661              :          * exactly one row, throw an error.  If STRICT was not specified, then
    4662              :          * allow the query to find any number of rows.
    4663              :          */
    4664         3944 :         if (n == 0)
    4665              :         {
    4666            8 :             if (stmt->strict)
    4667              :             {
    4668              :                 char       *errdetail;
    4669              : 
    4670            8 :                 if (estate->func->print_strict_params)
    4671            4 :                     errdetail = format_preparedparamsdata(estate, paramLI);
    4672              :                 else
    4673            4 :                     errdetail = NULL;
    4674              : 
    4675            8 :                 ereport(ERROR,
    4676              :                         (errcode(ERRCODE_NO_DATA_FOUND),
    4677              :                          errmsg("query returned no rows"),
    4678              :                          errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
    4679              :             }
    4680              :             /* set the target to NULL(s) */
    4681            0 :             exec_move_row(estate, target, NULL, tuptab->tupdesc);
    4682              :         }
    4683              :         else
    4684              :         {
    4685         3936 :             if (n > 1 && stmt->strict)
    4686              :             {
    4687              :                 char       *errdetail;
    4688              : 
    4689           12 :                 if (estate->func->print_strict_params)
    4690            8 :                     errdetail = format_preparedparamsdata(estate, paramLI);
    4691              :                 else
    4692            4 :                     errdetail = NULL;
    4693              : 
    4694           12 :                 ereport(ERROR,
    4695              :                         (errcode(ERRCODE_TOO_MANY_ROWS),
    4696              :                          errmsg("query returned more than one row"),
    4697              :                          errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
    4698              :             }
    4699              : 
    4700              :             /* Put the first result row into the target */
    4701         3924 :             exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc);
    4702              :         }
    4703              :         /* clean up after exec_move_row() */
    4704         3924 :         exec_eval_cleanup(estate);
    4705              :     }
    4706              :     else
    4707              :     {
    4708              :         /*
    4709              :          * It might be a good idea to raise an error if the query returned
    4710              :          * tuples that are being ignored, but historically we have not done
    4711              :          * that.
    4712              :          */
    4713              :     }
    4714              : 
    4715              :     /* Release any result from SPI_execute, as well as transient data */
    4716        10967 :     SPI_freetuptable(SPI_tuptable);
    4717        10967 :     MemoryContextReset(stmt_mcontext);
    4718              : 
    4719        10967 :     return PLPGSQL_RC_OK;
    4720              : }
    4721              : 
    4722              : 
    4723              : /* ----------
    4724              :  * exec_stmt_dynfors            Execute a dynamic query, assign each
    4725              :  *                  tuple to a record or row and
    4726              :  *                  execute a group of statements
    4727              :  *                  for it.
    4728              :  * ----------
    4729              :  */
    4730              : static int
    4731         6387 : exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
    4732              : {
    4733              :     Portal      portal;
    4734              :     int         rc;
    4735              : 
    4736         6387 :     portal = exec_dynquery_with_params(estate, stmt->query, stmt->params,
    4737              :                                        NULL, CURSOR_OPT_NO_SCROLL);
    4738              : 
    4739              :     /*
    4740              :      * Execute the loop
    4741              :      */
    4742         6387 :     rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, true);
    4743              : 
    4744              :     /*
    4745              :      * Close the implicit cursor
    4746              :      */
    4747         6383 :     SPI_cursor_close(portal);
    4748              : 
    4749         6383 :     return rc;
    4750              : }
    4751              : 
    4752              : 
    4753              : /* ----------
    4754              :  * exec_stmt_open           Execute an OPEN cursor statement
    4755              :  * ----------
    4756              :  */
    4757              : static int
    4758           93 : exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
    4759              : {
    4760              :     PLpgSQL_var *curvar;
    4761           93 :     MemoryContext stmt_mcontext = NULL;
    4762           93 :     char       *curname = NULL;
    4763              :     PLpgSQL_expr *query;
    4764              :     Portal      portal;
    4765              :     ParamListInfo paramLI;
    4766              : 
    4767              :     /* ----------
    4768              :      * Get the cursor variable and if it has an assigned name, check
    4769              :      * that it's not in use currently.
    4770              :      * ----------
    4771              :      */
    4772           93 :     curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
    4773           93 :     if (!curvar->isnull)
    4774              :     {
    4775              :         MemoryContext oldcontext;
    4776              : 
    4777              :         /* We only need stmt_mcontext to hold the cursor name string */
    4778           16 :         stmt_mcontext = get_stmt_mcontext(estate);
    4779           16 :         oldcontext = MemoryContextSwitchTo(stmt_mcontext);
    4780           16 :         curname = TextDatumGetCString(curvar->value);
    4781           16 :         MemoryContextSwitchTo(oldcontext);
    4782              : 
    4783           16 :         if (SPI_cursor_find(curname) != NULL)
    4784            0 :             ereport(ERROR,
    4785              :                     (errcode(ERRCODE_DUPLICATE_CURSOR),
    4786              :                      errmsg("cursor \"%s\" already in use", curname)));
    4787              :     }
    4788              : 
    4789              :     /* ----------
    4790              :      * Process the OPEN according to its type.
    4791              :      * ----------
    4792              :      */
    4793           93 :     if (stmt->query != NULL)
    4794              :     {
    4795              :         /* ----------
    4796              :          * This is an OPEN refcursor FOR SELECT ...
    4797              :          *
    4798              :          * We just make sure the query is planned. The real work is
    4799              :          * done downstairs.
    4800              :          * ----------
    4801              :          */
    4802           33 :         query = stmt->query;
    4803           33 :         if (query->plan == NULL)
    4804           25 :             exec_prepare_plan(estate, query, stmt->cursor_options);
    4805              :     }
    4806           60 :     else if (stmt->dynquery != NULL)
    4807              :     {
    4808              :         /* ----------
    4809              :          * This is an OPEN refcursor FOR EXECUTE ...
    4810              :          * ----------
    4811              :          */
    4812           12 :         portal = exec_dynquery_with_params(estate,
    4813              :                                            stmt->dynquery,
    4814              :                                            stmt->params,
    4815              :                                            curname,
    4816              :                                            stmt->cursor_options);
    4817              : 
    4818              :         /*
    4819              :          * If cursor variable was NULL, store the generated portal name in it,
    4820              :          * after verifying it's okay to assign to.
    4821              :          *
    4822              :          * Note: exec_dynquery_with_params already reset the stmt_mcontext, so
    4823              :          * curname is a dangling pointer here; but testing it for nullness is
    4824              :          * OK.
    4825              :          */
    4826           12 :         if (curname == NULL)
    4827              :         {
    4828           12 :             exec_check_assignable(estate, stmt->curvar);
    4829           12 :             assign_text_var(estate, curvar, portal->name);
    4830              :         }
    4831              : 
    4832           12 :         return PLPGSQL_RC_OK;
    4833              :     }
    4834              :     else
    4835              :     {
    4836              :         /* ----------
    4837              :          * This is an OPEN cursor
    4838              :          *
    4839              :          * Note: parser should already have checked that statement supplies
    4840              :          * args iff cursor needs them, but we check again to be safe.
    4841              :          * ----------
    4842              :          */
    4843           48 :         if (stmt->argquery != NULL)
    4844              :         {
    4845              :             /* ----------
    4846              :              * OPEN CURSOR with args.  We fake a SELECT ... INTO ...
    4847              :              * statement to evaluate the args and put 'em into the
    4848              :              * internal row.
    4849              :              * ----------
    4850              :              */
    4851              :             PLpgSQL_stmt_execsql set_args;
    4852              : 
    4853           32 :             if (curvar->cursor_explicit_argrow < 0)
    4854            0 :                 ereport(ERROR,
    4855              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    4856              :                          errmsg("arguments given for cursor without arguments")));
    4857              : 
    4858           32 :             memset(&set_args, 0, sizeof(set_args));
    4859           32 :             set_args.cmd_type = PLPGSQL_STMT_EXECSQL;
    4860           32 :             set_args.lineno = stmt->lineno;
    4861           32 :             set_args.sqlstmt = stmt->argquery;
    4862           32 :             set_args.into = true;
    4863              :             /* XXX historically this has not been STRICT */
    4864           32 :             set_args.target = (PLpgSQL_variable *)
    4865           32 :                 (estate->datums[curvar->cursor_explicit_argrow]);
    4866              : 
    4867           32 :             if (exec_stmt_execsql(estate, &set_args) != PLPGSQL_RC_OK)
    4868            0 :                 elog(ERROR, "open cursor failed during argument processing");
    4869              :         }
    4870              :         else
    4871              :         {
    4872           16 :             if (curvar->cursor_explicit_argrow >= 0)
    4873            0 :                 ereport(ERROR,
    4874              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    4875              :                          errmsg("arguments required for cursor")));
    4876              :         }
    4877              : 
    4878           44 :         query = curvar->cursor_explicit_expr;
    4879           44 :         if (query->plan == NULL)
    4880           36 :             exec_prepare_plan(estate, query, curvar->cursor_options);
    4881              :     }
    4882              : 
    4883              :     /*
    4884              :      * Set up ParamListInfo for this query
    4885              :      */
    4886           77 :     paramLI = setup_param_list(estate, query);
    4887              : 
    4888              :     /*
    4889              :      * Open the cursor (the paramlist will get copied into the portal)
    4890              :      */
    4891           77 :     portal = SPI_cursor_open_with_paramlist(curname, query->plan,
    4892              :                                             paramLI,
    4893           77 :                                             estate->readonly_func);
    4894           77 :     if (portal == NULL)
    4895            0 :         elog(ERROR, "could not open cursor: %s",
    4896              :              SPI_result_code_string(SPI_result));
    4897              : 
    4898              :     /*
    4899              :      * If cursor variable was NULL, store the generated portal name in it,
    4900              :      * after verifying it's okay to assign to.
    4901              :      */
    4902           77 :     if (curname == NULL)
    4903              :     {
    4904           61 :         exec_check_assignable(estate, stmt->curvar);
    4905           57 :         assign_text_var(estate, curvar, portal->name);
    4906              :     }
    4907              : 
    4908              :     /* If we had any transient data, clean it up */
    4909           73 :     exec_eval_cleanup(estate);
    4910           73 :     if (stmt_mcontext)
    4911           16 :         MemoryContextReset(stmt_mcontext);
    4912              : 
    4913           73 :     return PLPGSQL_RC_OK;
    4914              : }
    4915              : 
    4916              : 
    4917              : /* ----------
    4918              :  * exec_stmt_fetch          Fetch from a cursor into a target, or just
    4919              :  *                          move the current position of the cursor
    4920              :  * ----------
    4921              :  */
    4922              : static int
    4923          229 : exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
    4924              : {
    4925              :     PLpgSQL_var *curvar;
    4926          229 :     long        how_many = stmt->how_many;
    4927              :     SPITupleTable *tuptab;
    4928              :     Portal      portal;
    4929              :     char       *curname;
    4930              :     uint64      n;
    4931              :     MemoryContext oldcontext;
    4932              : 
    4933              :     /* ----------
    4934              :      * Get the portal of the cursor by name
    4935              :      * ----------
    4936              :      */
    4937          229 :     curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
    4938          229 :     if (curvar->isnull)
    4939            0 :         ereport(ERROR,
    4940              :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    4941              :                  errmsg("cursor variable \"%s\" is null", curvar->refname)));
    4942              : 
    4943              :     /* Use eval_mcontext for short-lived string */
    4944          229 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    4945          229 :     curname = TextDatumGetCString(curvar->value);
    4946          229 :     MemoryContextSwitchTo(oldcontext);
    4947              : 
    4948          229 :     portal = SPI_cursor_find(curname);
    4949          229 :     if (portal == NULL)
    4950            0 :         ereport(ERROR,
    4951              :                 (errcode(ERRCODE_UNDEFINED_CURSOR),
    4952              :                  errmsg("cursor \"%s\" does not exist", curname)));
    4953              : 
    4954              :     /* Calculate position for FETCH_RELATIVE or FETCH_ABSOLUTE */
    4955          229 :     if (stmt->expr)
    4956              :     {
    4957              :         bool        isnull;
    4958              : 
    4959              :         /* XXX should be doing this in LONG not INT width */
    4960           44 :         how_many = exec_eval_integer(estate, stmt->expr, &isnull);
    4961              : 
    4962           44 :         if (isnull)
    4963            0 :             ereport(ERROR,
    4964              :                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    4965              :                      errmsg("relative or absolute cursor position is null")));
    4966              : 
    4967           44 :         exec_eval_cleanup(estate);
    4968              :     }
    4969              : 
    4970          229 :     if (!stmt->is_move)
    4971              :     {
    4972              :         PLpgSQL_variable *target;
    4973              : 
    4974              :         /* ----------
    4975              :          * Fetch 1 tuple from the cursor
    4976              :          * ----------
    4977              :          */
    4978          201 :         SPI_scroll_cursor_fetch(portal, stmt->direction, how_many);
    4979          197 :         tuptab = SPI_tuptable;
    4980          197 :         n = SPI_processed;
    4981              : 
    4982              :         /* ----------
    4983              :          * Set the target appropriately.
    4984              :          * ----------
    4985              :          */
    4986          197 :         target = (PLpgSQL_variable *) estate->datums[stmt->target->dno];
    4987          197 :         if (n == 0)
    4988           32 :             exec_move_row(estate, target, NULL, tuptab->tupdesc);
    4989              :         else
    4990          165 :             exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc);
    4991              : 
    4992          197 :         exec_eval_cleanup(estate);
    4993          197 :         SPI_freetuptable(tuptab);
    4994              :     }
    4995              :     else
    4996              :     {
    4997              :         /* Move the cursor */
    4998           28 :         SPI_scroll_cursor_move(portal, stmt->direction, how_many);
    4999           28 :         n = SPI_processed;
    5000              :     }
    5001              : 
    5002              :     /* Set the ROW_COUNT and the global FOUND variable appropriately. */
    5003          225 :     estate->eval_processed = n;
    5004          225 :     exec_set_found(estate, n != 0);
    5005              : 
    5006          225 :     return PLPGSQL_RC_OK;
    5007              : }
    5008              : 
    5009              : /* ----------
    5010              :  * exec_stmt_close          Close a cursor
    5011              :  * ----------
    5012              :  */
    5013              : static int
    5014           48 : exec_stmt_close(PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
    5015              : {
    5016              :     PLpgSQL_var *curvar;
    5017              :     Portal      portal;
    5018              :     char       *curname;
    5019              :     MemoryContext oldcontext;
    5020              : 
    5021              :     /* ----------
    5022              :      * Get the portal of the cursor by name
    5023              :      * ----------
    5024              :      */
    5025           48 :     curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
    5026           48 :     if (curvar->isnull)
    5027            0 :         ereport(ERROR,
    5028              :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    5029              :                  errmsg("cursor variable \"%s\" is null", curvar->refname)));
    5030              : 
    5031              :     /* Use eval_mcontext for short-lived string */
    5032           48 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    5033           48 :     curname = TextDatumGetCString(curvar->value);
    5034           48 :     MemoryContextSwitchTo(oldcontext);
    5035              : 
    5036           48 :     portal = SPI_cursor_find(curname);
    5037           48 :     if (portal == NULL)
    5038            0 :         ereport(ERROR,
    5039              :                 (errcode(ERRCODE_UNDEFINED_CURSOR),
    5040              :                  errmsg("cursor \"%s\" does not exist", curname)));
    5041              : 
    5042              :     /* ----------
    5043              :      * And close it.
    5044              :      * ----------
    5045              :      */
    5046           48 :     SPI_cursor_close(portal);
    5047              : 
    5048           48 :     return PLPGSQL_RC_OK;
    5049              : }
    5050              : 
    5051              : /*
    5052              :  * exec_stmt_commit
    5053              :  *
    5054              :  * Commit the transaction.
    5055              :  */
    5056              : static int
    5057         2083 : exec_stmt_commit(PLpgSQL_execstate *estate, PLpgSQL_stmt_commit *stmt)
    5058              : {
    5059         2083 :     if (stmt->chain)
    5060            2 :         SPI_commit_and_chain();
    5061              :     else
    5062         2081 :         SPI_commit();
    5063              : 
    5064              :     /*
    5065              :      * We need to build new simple-expression infrastructure, since the old
    5066              :      * data structures are gone.
    5067              :      */
    5068         2072 :     estate->simple_eval_estate = NULL;
    5069         2072 :     estate->simple_eval_resowner = NULL;
    5070         2072 :     plpgsql_create_econtext(estate);
    5071              : 
    5072         2072 :     return PLPGSQL_RC_OK;
    5073              : }
    5074              : 
    5075              : /*
    5076              :  * exec_stmt_rollback
    5077              :  *
    5078              :  * Abort the transaction.
    5079              :  */
    5080              : static int
    5081           53 : exec_stmt_rollback(PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
    5082              : {
    5083           53 :     if (stmt->chain)
    5084            2 :         SPI_rollback_and_chain();
    5085              :     else
    5086           51 :         SPI_rollback();
    5087              : 
    5088              :     /*
    5089              :      * We need to build new simple-expression infrastructure, since the old
    5090              :      * data structures are gone.
    5091              :      */
    5092           50 :     estate->simple_eval_estate = NULL;
    5093           50 :     estate->simple_eval_resowner = NULL;
    5094           50 :     plpgsql_create_econtext(estate);
    5095              : 
    5096           50 :     return PLPGSQL_RC_OK;
    5097              : }
    5098              : 
    5099              : /* ----------
    5100              :  * exec_assign_expr         Put an expression's result into a variable.
    5101              :  * ----------
    5102              :  */
    5103              : static void
    5104        66471 : exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target,
    5105              :                  PLpgSQL_expr *expr)
    5106              : {
    5107              :     Datum       value;
    5108              :     bool        isnull;
    5109              :     Oid         valtype;
    5110              :     int32       valtypmod;
    5111              : 
    5112              :     /*
    5113              :      * If first time through, create a plan for this expression.
    5114              :      */
    5115        66471 :     if (expr->plan == NULL)
    5116         2765 :         exec_prepare_plan(estate, expr, 0);
    5117              : 
    5118        66449 :     value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
    5119        66326 :     exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
    5120        66292 :     exec_eval_cleanup(estate);
    5121        66292 : }
    5122              : 
    5123              : 
    5124              : /* ----------
    5125              :  * exec_assign_c_string     Put a C string into a text variable.
    5126              :  *
    5127              :  * We take a NULL pointer as signifying empty string, not SQL null.
    5128              :  *
    5129              :  * As with the underlying exec_assign_value, caller is expected to do
    5130              :  * exec_eval_cleanup later.
    5131              :  * ----------
    5132              :  */
    5133              : static void
    5134           85 : exec_assign_c_string(PLpgSQL_execstate *estate, PLpgSQL_datum *target,
    5135              :                      const char *str)
    5136              : {
    5137              :     text       *value;
    5138              :     MemoryContext oldcontext;
    5139              : 
    5140              :     /* Use eval_mcontext for short-lived text value */
    5141           85 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    5142           85 :     if (str != NULL)
    5143           85 :         value = cstring_to_text(str);
    5144              :     else
    5145            0 :         value = cstring_to_text("");
    5146           85 :     MemoryContextSwitchTo(oldcontext);
    5147              : 
    5148           85 :     exec_assign_value(estate, target, PointerGetDatum(value), false,
    5149              :                       TEXTOID, -1);
    5150           85 : }
    5151              : 
    5152              : 
    5153              : /* ----------
    5154              :  * exec_assign_value            Put a value into a target datum
    5155              :  *
    5156              :  * Note: in some code paths, this will leak memory in the eval_mcontext;
    5157              :  * we assume that will be cleaned up later by exec_eval_cleanup.  We cannot
    5158              :  * call exec_eval_cleanup here for fear of destroying the input Datum value.
    5159              :  * ----------
    5160              :  */
    5161              : static void
    5162       116527 : exec_assign_value(PLpgSQL_execstate *estate,
    5163              :                   PLpgSQL_datum *target,
    5164              :                   Datum value, bool isNull,
    5165              :                   Oid valtype, int32 valtypmod)
    5166              : {
    5167       116527 :     switch (target->dtype)
    5168              :     {
    5169       114554 :         case PLPGSQL_DTYPE_VAR:
    5170              :         case PLPGSQL_DTYPE_PROMISE:
    5171              :             {
    5172              :                 /*
    5173              :                  * Target is a variable
    5174              :                  */
    5175       114554 :                 PLpgSQL_var *var = (PLpgSQL_var *) target;
    5176              :                 Datum       newvalue;
    5177              : 
    5178       114554 :                 newvalue = exec_cast_value(estate,
    5179              :                                            value,
    5180              :                                            &isNull,
    5181              :                                            valtype,
    5182              :                                            valtypmod,
    5183       114554 :                                            var->datatype->typoid,
    5184       114554 :                                            var->datatype->atttypmod);
    5185              : 
    5186       114538 :                 if (isNull && var->notnull)
    5187            6 :                     ereport(ERROR,
    5188              :                             (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    5189              :                              errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
    5190              :                                     var->refname)));
    5191              : 
    5192              :                 /*
    5193              :                  * If type is by-reference, copy the new value (which is
    5194              :                  * probably in the eval_mcontext) into the procedure's main
    5195              :                  * memory context.  But if it's a read/write reference to an
    5196              :                  * expanded object, no physical copy needs to happen; at most
    5197              :                  * we need to reparent the object's memory context.
    5198              :                  *
    5199              :                  * If it's an array, we force the value to be stored in R/W
    5200              :                  * expanded form.  This wins if the function later does, say,
    5201              :                  * a lot of array subscripting operations on the variable, and
    5202              :                  * otherwise might lose.  We might need to use a different
    5203              :                  * heuristic, but it's too soon to tell.  Also, are there
    5204              :                  * cases where it'd be useful to force non-array values into
    5205              :                  * expanded form?
    5206              :                  */
    5207       114532 :                 if (!var->datatype->typbyval && !isNull)
    5208              :                 {
    5209        79996 :                     if (var->datatype->typisarray &&
    5210         6978 :                         !VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(newvalue)))
    5211              :                     {
    5212              :                         /* array and not already R/W, so apply expand_array */
    5213         6853 :                         newvalue = expand_array(newvalue,
    5214              :                                                 estate->datum_context,
    5215              :                                                 NULL);
    5216              :                     }
    5217              :                     else
    5218              :                     {
    5219              :                         /* else transfer value if R/W, else just datumCopy */
    5220        73143 :                         newvalue = datumTransfer(newvalue,
    5221              :                                                  false,
    5222        73143 :                                                  var->datatype->typlen);
    5223              :                     }
    5224              :                 }
    5225              : 
    5226              :                 /*
    5227              :                  * Now free the old value, if any, and assign the new one. But
    5228              :                  * skip the assignment if old and new values are the same.
    5229              :                  * Note that for expanded objects, this test is necessary and
    5230              :                  * cannot reliably be made any earlier; we have to be looking
    5231              :                  * at the object's standard R/W pointer to be sure pointer
    5232              :                  * equality is meaningful.
    5233              :                  *
    5234              :                  * Also, if it's a promise variable, we should disarm the
    5235              :                  * promise in any case --- otherwise, assigning null to an
    5236              :                  * armed promise variable would fail to disarm the promise.
    5237              :                  */
    5238       114532 :                 if (var->value != newvalue || var->isnull || isNull)
    5239       112745 :                     assign_simple_var(estate, var, newvalue, isNull,
    5240       112745 :                                       (!var->datatype->typbyval && !isNull));
    5241              :                 else
    5242         1787 :                     var->promise = PLPGSQL_PROMISE_NONE;
    5243       114532 :                 break;
    5244              :             }
    5245              : 
    5246           28 :         case PLPGSQL_DTYPE_ROW:
    5247              :             {
    5248              :                 /*
    5249              :                  * Target is a row variable
    5250              :                  */
    5251           28 :                 PLpgSQL_row *row = (PLpgSQL_row *) target;
    5252              : 
    5253           28 :                 if (isNull)
    5254              :                 {
    5255              :                     /* If source is null, just assign nulls to the row */
    5256            0 :                     exec_move_row(estate, (PLpgSQL_variable *) row,
    5257              :                                   NULL, NULL);
    5258              :                 }
    5259              :                 else
    5260              :                 {
    5261              :                     /* Source must be of RECORD or composite type */
    5262           28 :                     if (!type_is_rowtype(valtype))
    5263            0 :                         ereport(ERROR,
    5264              :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    5265              :                                  errmsg("cannot assign non-composite value to a row variable")));
    5266           28 :                     exec_move_row_from_datum(estate, (PLpgSQL_variable *) row,
    5267              :                                              value);
    5268              :                 }
    5269           28 :                 break;
    5270              :             }
    5271              : 
    5272          438 :         case PLPGSQL_DTYPE_REC:
    5273              :             {
    5274              :                 /*
    5275              :                  * Target is a record variable
    5276              :                  */
    5277          438 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
    5278              : 
    5279          438 :                 if (isNull)
    5280              :                 {
    5281           89 :                     if (rec->notnull)
    5282            4 :                         ereport(ERROR,
    5283              :                                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    5284              :                                  errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
    5285              :                                         rec->refname)));
    5286              : 
    5287              :                     /* Set variable to a simple NULL */
    5288           85 :                     exec_move_row(estate, (PLpgSQL_variable *) rec,
    5289              :                                   NULL, NULL);
    5290              :                 }
    5291              :                 else
    5292              :                 {
    5293              :                     /* Source must be of RECORD or composite type */
    5294          349 :                     if (!type_is_rowtype(valtype))
    5295            0 :                         ereport(ERROR,
    5296              :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    5297              :                                  errmsg("cannot assign non-composite value to a record variable")));
    5298          349 :                     exec_move_row_from_datum(estate, (PLpgSQL_variable *) rec,
    5299              :                                              value);
    5300              :                 }
    5301          425 :                 break;
    5302              :             }
    5303              : 
    5304         1507 :         case PLPGSQL_DTYPE_RECFIELD:
    5305              :             {
    5306              :                 /*
    5307              :                  * Target is a field of a record
    5308              :                  */
    5309         1507 :                 PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target;
    5310              :                 PLpgSQL_rec *rec;
    5311              :                 ExpandedRecordHeader *erh;
    5312              : 
    5313         1507 :                 rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    5314         1507 :                 erh = rec->erh;
    5315              : 
    5316              :                 /*
    5317              :                  * If record variable is NULL, instantiate it if it has a
    5318              :                  * named composite type, else complain.  (This won't change
    5319              :                  * the logical state of the record, but if we successfully
    5320              :                  * assign below, the unassigned fields will all become NULLs.)
    5321              :                  */
    5322         1507 :                 if (erh == NULL)
    5323              :                 {
    5324           37 :                     instantiate_empty_record_variable(estate, rec);
    5325           36 :                     erh = rec->erh;
    5326              :                 }
    5327              : 
    5328              :                 /*
    5329              :                  * Look up the field's properties if we have not already, or
    5330              :                  * if the tuple descriptor ID changed since last time.
    5331              :                  */
    5332         1506 :                 if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
    5333              :                 {
    5334           21 :                     if (!expanded_record_lookup_field(erh,
    5335           21 :                                                       recfield->fieldname,
    5336              :                                                       &recfield->finfo))
    5337            1 :                         ereport(ERROR,
    5338              :                                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    5339              :                                  errmsg("record \"%s\" has no field \"%s\"",
    5340              :                                         rec->refname, recfield->fieldname)));
    5341           20 :                     recfield->rectupledescid = erh->er_tupdesc_id;
    5342              :                 }
    5343              : 
    5344              :                 /* We don't support assignments to system columns. */
    5345         1505 :                 if (recfield->finfo.fnumber <= 0)
    5346            0 :                     ereport(ERROR,
    5347              :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5348              :                              errmsg("cannot assign to system column \"%s\"",
    5349              :                                     recfield->fieldname)));
    5350              : 
    5351              :                 /* Cast the new value to the right type, if needed. */
    5352         1505 :                 value = exec_cast_value(estate,
    5353              :                                         value,
    5354              :                                         &isNull,
    5355              :                                         valtype,
    5356              :                                         valtypmod,
    5357              :                                         recfield->finfo.ftypeid,
    5358              :                                         recfield->finfo.ftypmod);
    5359              : 
    5360              :                 /* And assign it. */
    5361         1505 :                 expanded_record_set_field(erh, recfield->finfo.fnumber,
    5362              :                                           value, isNull, !estate->atomic);
    5363         1502 :                 break;
    5364              :             }
    5365              : 
    5366            0 :         default:
    5367            0 :             elog(ERROR, "unrecognized dtype: %d", target->dtype);
    5368              :     }
    5369       116487 : }
    5370              : 
    5371              : /*
    5372              :  * exec_eval_datum              Get current value of a PLpgSQL_datum
    5373              :  *
    5374              :  * The type oid, typmod, value in Datum format, and null flag are returned.
    5375              :  *
    5376              :  * At present this doesn't handle PLpgSQL_expr datums; that's not needed
    5377              :  * because we never pass references to such datums to SPI.
    5378              :  *
    5379              :  * NOTE: the returned Datum points right at the stored value in the case of
    5380              :  * pass-by-reference datatypes.  Generally callers should take care not to
    5381              :  * modify the stored value.  Some callers intentionally manipulate variables
    5382              :  * referenced by R/W expanded pointers, though; it is those callers'
    5383              :  * responsibility that the results are semantically OK.
    5384              :  *
    5385              :  * In some cases we have to palloc a return value, and in such cases we put
    5386              :  * it into the estate's eval_mcontext.
    5387              :  */
    5388              : static void
    5389        48879 : exec_eval_datum(PLpgSQL_execstate *estate,
    5390              :                 PLpgSQL_datum *datum,
    5391              :                 Oid *typeid,
    5392              :                 int32 *typetypmod,
    5393              :                 Datum *value,
    5394              :                 bool *isnull)
    5395              : {
    5396              :     MemoryContext oldcontext;
    5397              : 
    5398        48879 :     switch (datum->dtype)
    5399              :     {
    5400        16647 :         case PLPGSQL_DTYPE_PROMISE:
    5401              :             /* fulfill promise if needed, then handle like regular var */
    5402        16647 :             plpgsql_fulfill_promise(estate, (PLpgSQL_var *) datum);
    5403              : 
    5404              :             pg_fallthrough;
    5405              : 
    5406        31980 :         case PLPGSQL_DTYPE_VAR:
    5407              :             {
    5408        31980 :                 PLpgSQL_var *var = (PLpgSQL_var *) datum;
    5409              : 
    5410        31980 :                 *typeid = var->datatype->typoid;
    5411        31980 :                 *typetypmod = var->datatype->atttypmod;
    5412        31980 :                 *value = var->value;
    5413        31980 :                 *isnull = var->isnull;
    5414        31980 :                 break;
    5415              :             }
    5416              : 
    5417         4096 :         case PLPGSQL_DTYPE_ROW:
    5418              :             {
    5419         4096 :                 PLpgSQL_row *row = (PLpgSQL_row *) datum;
    5420              :                 HeapTuple   tup;
    5421              : 
    5422              :                 /* We get here if there are multiple OUT parameters */
    5423         4096 :                 if (!row->rowtupdesc)    /* should not happen */
    5424            0 :                     elog(ERROR, "row variable has no tupdesc");
    5425              :                 /* Make sure we have a valid type/typmod setting */
    5426         4096 :                 BlessTupleDesc(row->rowtupdesc);
    5427         4096 :                 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    5428         4096 :                 tup = make_tuple_from_row(estate, row, row->rowtupdesc);
    5429         4096 :                 if (tup == NULL)    /* should not happen */
    5430            0 :                     elog(ERROR, "row not compatible with its own tupdesc");
    5431         4096 :                 *typeid = row->rowtupdesc->tdtypeid;
    5432         4096 :                 *typetypmod = row->rowtupdesc->tdtypmod;
    5433         4096 :                 *value = HeapTupleGetDatum(tup);
    5434         4096 :                 *isnull = false;
    5435         4096 :                 MemoryContextSwitchTo(oldcontext);
    5436         4096 :                 break;
    5437              :             }
    5438              : 
    5439        11255 :         case PLPGSQL_DTYPE_REC:
    5440              :             {
    5441        11255 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
    5442              : 
    5443        11255 :                 if (rec->erh == NULL)
    5444              :                 {
    5445              :                     /* Treat uninstantiated record as a simple NULL */
    5446          124 :                     *value = (Datum) 0;
    5447          124 :                     *isnull = true;
    5448              :                     /* Report variable's declared type */
    5449          124 :                     *typeid = rec->rectypeid;
    5450          124 :                     *typetypmod = -1;
    5451              :                 }
    5452              :                 else
    5453              :                 {
    5454        11131 :                     if (ExpandedRecordIsEmpty(rec->erh))
    5455              :                     {
    5456              :                         /* Empty record is also a NULL */
    5457          215 :                         *value = (Datum) 0;
    5458          215 :                         *isnull = true;
    5459              :                     }
    5460              :                     else
    5461              :                     {
    5462        10916 :                         *value = ExpandedRecordGetDatum(rec->erh);
    5463        10916 :                         *isnull = false;
    5464              :                     }
    5465        11131 :                     if (rec->rectypeid != RECORDOID)
    5466              :                     {
    5467              :                         /* Report variable's declared type, if not RECORD */
    5468          689 :                         *typeid = rec->rectypeid;
    5469          689 :                         *typetypmod = -1;
    5470              :                     }
    5471              :                     else
    5472              :                     {
    5473              :                         /* Report record's actual type if declared RECORD */
    5474        10442 :                         *typeid = rec->erh->er_typeid;
    5475        10442 :                         *typetypmod = rec->erh->er_typmod;
    5476              :                     }
    5477              :                 }
    5478        11255 :                 break;
    5479              :             }
    5480              : 
    5481         1548 :         case PLPGSQL_DTYPE_RECFIELD:
    5482              :             {
    5483         1548 :                 PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
    5484              :                 PLpgSQL_rec *rec;
    5485              :                 ExpandedRecordHeader *erh;
    5486              : 
    5487         1548 :                 rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    5488         1548 :                 erh = rec->erh;
    5489              : 
    5490              :                 /*
    5491              :                  * If record variable is NULL, instantiate it if it has a
    5492              :                  * named composite type, else complain.  (This won't change
    5493              :                  * the logical state of the record: it's still NULL.)
    5494              :                  */
    5495         1548 :                 if (erh == NULL)
    5496              :                 {
    5497            0 :                     instantiate_empty_record_variable(estate, rec);
    5498            0 :                     erh = rec->erh;
    5499              :                 }
    5500              : 
    5501              :                 /*
    5502              :                  * Look up the field's properties if we have not already, or
    5503              :                  * if the tuple descriptor ID changed since last time.
    5504              :                  */
    5505         1548 :                 if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
    5506              :                 {
    5507            0 :                     if (!expanded_record_lookup_field(erh,
    5508            0 :                                                       recfield->fieldname,
    5509              :                                                       &recfield->finfo))
    5510            0 :                         ereport(ERROR,
    5511              :                                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    5512              :                                  errmsg("record \"%s\" has no field \"%s\"",
    5513              :                                         rec->refname, recfield->fieldname)));
    5514            0 :                     recfield->rectupledescid = erh->er_tupdesc_id;
    5515              :                 }
    5516              : 
    5517              :                 /* Report type data. */
    5518         1548 :                 *typeid = recfield->finfo.ftypeid;
    5519         1548 :                 *typetypmod = recfield->finfo.ftypmod;
    5520              : 
    5521              :                 /* And fetch the field value. */
    5522         1548 :                 *value = expanded_record_get_field(erh,
    5523              :                                                    recfield->finfo.fnumber,
    5524              :                                                    isnull);
    5525         1548 :                 break;
    5526              :             }
    5527              : 
    5528            0 :         default:
    5529            0 :             elog(ERROR, "unrecognized dtype: %d", datum->dtype);
    5530              :     }
    5531        48879 : }
    5532              : 
    5533              : /*
    5534              :  * plpgsql_exec_get_datum_type              Get datatype of a PLpgSQL_datum
    5535              :  *
    5536              :  * This is the same logic as in exec_eval_datum, but we skip acquiring
    5537              :  * the actual value of the variable.  Also, needn't support DTYPE_ROW.
    5538              :  */
    5539              : Oid
    5540          101 : plpgsql_exec_get_datum_type(PLpgSQL_execstate *estate,
    5541              :                             PLpgSQL_datum *datum)
    5542              : {
    5543              :     Oid         typeid;
    5544              : 
    5545          101 :     switch (datum->dtype)
    5546              :     {
    5547          101 :         case PLPGSQL_DTYPE_VAR:
    5548              :         case PLPGSQL_DTYPE_PROMISE:
    5549              :             {
    5550          101 :                 PLpgSQL_var *var = (PLpgSQL_var *) datum;
    5551              : 
    5552          101 :                 typeid = var->datatype->typoid;
    5553          101 :                 break;
    5554              :             }
    5555              : 
    5556            0 :         case PLPGSQL_DTYPE_REC:
    5557              :             {
    5558            0 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
    5559              : 
    5560            0 :                 if (rec->erh == NULL || rec->rectypeid != RECORDOID)
    5561              :                 {
    5562              :                     /* Report variable's declared type */
    5563            0 :                     typeid = rec->rectypeid;
    5564              :                 }
    5565              :                 else
    5566              :                 {
    5567              :                     /* Report record's actual type if declared RECORD */
    5568            0 :                     typeid = rec->erh->er_typeid;
    5569              :                 }
    5570            0 :                 break;
    5571              :             }
    5572              : 
    5573            0 :         case PLPGSQL_DTYPE_RECFIELD:
    5574              :             {
    5575            0 :                 PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
    5576              :                 PLpgSQL_rec *rec;
    5577              : 
    5578            0 :                 rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    5579              : 
    5580              :                 /*
    5581              :                  * If record variable is NULL, instantiate it if it has a
    5582              :                  * named composite type, else complain.  (This won't change
    5583              :                  * the logical state of the record: it's still NULL.)
    5584              :                  */
    5585            0 :                 if (rec->erh == NULL)
    5586            0 :                     instantiate_empty_record_variable(estate, rec);
    5587              : 
    5588              :                 /*
    5589              :                  * Look up the field's properties if we have not already, or
    5590              :                  * if the tuple descriptor ID changed since last time.
    5591              :                  */
    5592            0 :                 if (unlikely(recfield->rectupledescid != rec->erh->er_tupdesc_id))
    5593              :                 {
    5594            0 :                     if (!expanded_record_lookup_field(rec->erh,
    5595            0 :                                                       recfield->fieldname,
    5596              :                                                       &recfield->finfo))
    5597            0 :                         ereport(ERROR,
    5598              :                                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    5599              :                                  errmsg("record \"%s\" has no field \"%s\"",
    5600              :                                         rec->refname, recfield->fieldname)));
    5601            0 :                     recfield->rectupledescid = rec->erh->er_tupdesc_id;
    5602              :                 }
    5603              : 
    5604            0 :                 typeid = recfield->finfo.ftypeid;
    5605            0 :                 break;
    5606              :             }
    5607              : 
    5608            0 :         default:
    5609            0 :             elog(ERROR, "unrecognized dtype: %d", datum->dtype);
    5610              :             typeid = InvalidOid;    /* keep compiler quiet */
    5611              :             break;
    5612              :     }
    5613              : 
    5614          101 :     return typeid;
    5615              : }
    5616              : 
    5617              : /*
    5618              :  * plpgsql_exec_get_datum_type_info         Get datatype etc of a PLpgSQL_datum
    5619              :  *
    5620              :  * An extended version of plpgsql_exec_get_datum_type, which also retrieves the
    5621              :  * typmod and collation of the datum.  Note however that we don't report the
    5622              :  * possibly-mutable typmod of RECORD values, but say -1 always.
    5623              :  */
    5624              : void
    5625        23041 : plpgsql_exec_get_datum_type_info(PLpgSQL_execstate *estate,
    5626              :                                  PLpgSQL_datum *datum,
    5627              :                                  Oid *typeId, int32 *typMod, Oid *collation)
    5628              : {
    5629        23041 :     switch (datum->dtype)
    5630              :     {
    5631        17875 :         case PLPGSQL_DTYPE_VAR:
    5632              :         case PLPGSQL_DTYPE_PROMISE:
    5633              :             {
    5634        17875 :                 PLpgSQL_var *var = (PLpgSQL_var *) datum;
    5635              : 
    5636        17875 :                 *typeId = var->datatype->typoid;
    5637        17875 :                 *typMod = var->datatype->atttypmod;
    5638        17875 :                 *collation = var->datatype->collation;
    5639        17875 :                 break;
    5640              :             }
    5641              : 
    5642         1652 :         case PLPGSQL_DTYPE_REC:
    5643              :             {
    5644         1652 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
    5645              : 
    5646         1652 :                 if (rec->erh == NULL || rec->rectypeid != RECORDOID)
    5647              :                 {
    5648              :                     /* Report variable's declared type */
    5649          322 :                     *typeId = rec->rectypeid;
    5650          322 :                     *typMod = -1;
    5651              :                 }
    5652              :                 else
    5653              :                 {
    5654              :                     /* Report record's actual type if declared RECORD */
    5655         1330 :                     *typeId = rec->erh->er_typeid;
    5656              :                     /* do NOT return the mutable typmod of a RECORD variable */
    5657         1330 :                     *typMod = -1;
    5658              :                 }
    5659              :                 /* composite types are never collatable */
    5660         1652 :                 *collation = InvalidOid;
    5661         1652 :                 break;
    5662              :             }
    5663              : 
    5664         3514 :         case PLPGSQL_DTYPE_RECFIELD:
    5665              :             {
    5666         3514 :                 PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
    5667              :                 PLpgSQL_rec *rec;
    5668              : 
    5669         3514 :                 rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    5670              : 
    5671              :                 /*
    5672              :                  * If record variable is NULL, instantiate it if it has a
    5673              :                  * named composite type, else complain.  (This won't change
    5674              :                  * the logical state of the record: it's still NULL.)
    5675              :                  */
    5676         3514 :                 if (rec->erh == NULL)
    5677           24 :                     instantiate_empty_record_variable(estate, rec);
    5678              : 
    5679              :                 /*
    5680              :                  * Look up the field's properties if we have not already, or
    5681              :                  * if the tuple descriptor ID changed since last time.
    5682              :                  */
    5683         3513 :                 if (unlikely(recfield->rectupledescid != rec->erh->er_tupdesc_id))
    5684              :                 {
    5685         2029 :                     if (!expanded_record_lookup_field(rec->erh,
    5686         2029 :                                                       recfield->fieldname,
    5687              :                                                       &recfield->finfo))
    5688           10 :                         ereport(ERROR,
    5689              :                                 (errcode(ERRCODE_UNDEFINED_COLUMN),
    5690              :                                  errmsg("record \"%s\" has no field \"%s\"",
    5691              :                                         rec->refname, recfield->fieldname)));
    5692         2019 :                     recfield->rectupledescid = rec->erh->er_tupdesc_id;
    5693              :                 }
    5694              : 
    5695         3503 :                 *typeId = recfield->finfo.ftypeid;
    5696         3503 :                 *typMod = recfield->finfo.ftypmod;
    5697         3503 :                 *collation = recfield->finfo.fcollation;
    5698         3503 :                 break;
    5699              :             }
    5700              : 
    5701            0 :         default:
    5702            0 :             elog(ERROR, "unrecognized dtype: %d", datum->dtype);
    5703              :             *typeId = InvalidOid;   /* keep compiler quiet */
    5704              :             *typMod = -1;
    5705              :             *collation = InvalidOid;
    5706              :             break;
    5707              :     }
    5708        23030 : }
    5709              : 
    5710              : /* ----------
    5711              :  * exec_eval_integer        Evaluate an expression, coerce result to int4
    5712              :  *
    5713              :  * Note we do not do exec_eval_cleanup here; the caller must do it at
    5714              :  * some later point.  (We do this because the caller may be holding the
    5715              :  * results of other, pass-by-reference, expression evaluations, such as
    5716              :  * an array value to be subscripted.)
    5717              :  * ----------
    5718              :  */
    5719              : static int
    5720           44 : exec_eval_integer(PLpgSQL_execstate *estate,
    5721              :                   PLpgSQL_expr *expr,
    5722              :                   bool *isNull)
    5723              : {
    5724              :     Datum       exprdatum;
    5725              :     Oid         exprtypeid;
    5726              :     int32       exprtypmod;
    5727              : 
    5728           44 :     exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
    5729           44 :     exprdatum = exec_cast_value(estate, exprdatum, isNull,
    5730              :                                 exprtypeid, exprtypmod,
    5731              :                                 INT4OID, -1);
    5732           44 :     return DatumGetInt32(exprdatum);
    5733              : }
    5734              : 
    5735              : /* ----------
    5736              :  * exec_eval_boolean        Evaluate an expression, coerce result to bool
    5737              :  *
    5738              :  * Note we do not do exec_eval_cleanup here; the caller must do it at
    5739              :  * some later point.
    5740              :  * ----------
    5741              :  */
    5742              : static bool
    5743        82446 : exec_eval_boolean(PLpgSQL_execstate *estate,
    5744              :                   PLpgSQL_expr *expr,
    5745              :                   bool *isNull)
    5746              : {
    5747              :     Datum       exprdatum;
    5748              :     Oid         exprtypeid;
    5749              :     int32       exprtypmod;
    5750              : 
    5751        82446 :     exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
    5752        82446 :     exprdatum = exec_cast_value(estate, exprdatum, isNull,
    5753              :                                 exprtypeid, exprtypmod,
    5754              :                                 BOOLOID, -1);
    5755        82446 :     return DatumGetBool(exprdatum);
    5756              : }
    5757              : 
    5758              : /* ----------
    5759              :  * exec_eval_expr           Evaluate an expression and return
    5760              :  *                  the result Datum, along with data type/typmod.
    5761              :  *
    5762              :  * NOTE: caller must do exec_eval_cleanup when done with the Datum.
    5763              :  * ----------
    5764              :  */
    5765              : static Datum
    5766       218710 : exec_eval_expr(PLpgSQL_execstate *estate,
    5767              :                PLpgSQL_expr *expr,
    5768              :                bool *isNull,
    5769              :                Oid *rettype,
    5770              :                int32 *rettypmod)
    5771              : {
    5772       218710 :     Datum       result = 0;
    5773              :     int         rc;
    5774              :     Form_pg_attribute attr;
    5775              : 
    5776              :     /*
    5777              :      * If first time through, create a plan for this expression.
    5778              :      */
    5779       218710 :     if (expr->plan == NULL)
    5780        12561 :         exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK);
    5781              : 
    5782              :     /*
    5783              :      * If this is a simple expression, bypass SPI and use the executor
    5784              :      * directly
    5785              :      */
    5786       218686 :     if (exec_eval_simple_expr(estate, expr,
    5787              :                               &result, isNull, rettype, rettypmod))
    5788       213218 :         return result;
    5789              : 
    5790              :     /*
    5791              :      * Else do it the hard way via exec_run_select
    5792              :      */
    5793         5310 :     rc = exec_run_select(estate, expr, 0, NULL);
    5794         5293 :     if (rc != SPI_OK_SELECT)
    5795            0 :         ereport(ERROR,
    5796              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    5797              :                  errmsg("query did not return data"),
    5798              :                  errcontext("query: %s", expr->query)));
    5799              : 
    5800              :     /*
    5801              :      * Check that the expression returns exactly one column...
    5802              :      */
    5803         5293 :     if (estate->eval_tuptable->tupdesc->natts != 1)
    5804            0 :         ereport(ERROR,
    5805              :                 (errcode(ERRCODE_SYNTAX_ERROR),
    5806              :                  errmsg_plural("query returned %d column",
    5807              :                                "query returned %d columns",
    5808              :                                estate->eval_tuptable->tupdesc->natts,
    5809              :                                estate->eval_tuptable->tupdesc->natts),
    5810              :                  errcontext("query: %s", expr->query)));
    5811              : 
    5812              :     /*
    5813              :      * ... and get the column's datatype.
    5814              :      */
    5815         5293 :     attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
    5816         5293 :     *rettype = attr->atttypid;
    5817         5293 :     *rettypmod = attr->atttypmod;
    5818              : 
    5819              :     /*
    5820              :      * If there are no rows selected, the result is a NULL of that type.
    5821              :      */
    5822         5293 :     if (estate->eval_processed == 0)
    5823              :     {
    5824            0 :         *isNull = true;
    5825            0 :         return (Datum) 0;
    5826              :     }
    5827              : 
    5828              :     /*
    5829              :      * Check that the expression returned no more than one row.
    5830              :      */
    5831         5293 :     if (estate->eval_processed != 1)
    5832            1 :         ereport(ERROR,
    5833              :                 (errcode(ERRCODE_CARDINALITY_VIOLATION),
    5834              :                  errmsg("query returned more than one row"),
    5835              :                  errcontext("query: %s", expr->query)));
    5836              : 
    5837              :     /*
    5838              :      * Return the single result Datum.
    5839              :      */
    5840         5292 :     return SPI_getbinval(estate->eval_tuptable->vals[0],
    5841         5292 :                          estate->eval_tuptable->tupdesc, 1, isNull);
    5842              : }
    5843              : 
    5844              : 
    5845              : /* ----------
    5846              :  * exec_run_select          Execute a select query
    5847              :  *
    5848              :  * Note: passing maxtuples different from 0 ("return all tuples") is
    5849              :  * deprecated because it will prevent parallel execution of the query.
    5850              :  * However, we retain the parameter in case we need it someday.
    5851              :  * ----------
    5852              :  */
    5853              : static int
    5854        10849 : exec_run_select(PLpgSQL_execstate *estate,
    5855              :                 PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
    5856              : {
    5857              :     ParamListInfo paramLI;
    5858              :     int         rc;
    5859              : 
    5860              :     /*
    5861              :      * On the first call for this expression generate the plan.
    5862              :      *
    5863              :      * If we don't need to return a portal, then we're just going to execute
    5864              :      * the query immediately, which means it's OK to use a parallel plan, even
    5865              :      * if the number of rows being fetched is limited.  If we do need to
    5866              :      * return a portal (i.e., this is for a FOR loop), the user's code might
    5867              :      * invoke additional operations inside the FOR loop, making parallel query
    5868              :      * unsafe.  In any case, we don't expect any cursor operations to be done,
    5869              :      * so specify NO_SCROLL for efficiency and semantic safety.
    5870              :      */
    5871        10849 :     if (expr->plan == NULL)
    5872              :     {
    5873          684 :         int         cursorOptions = CURSOR_OPT_NO_SCROLL;
    5874              : 
    5875          684 :         if (portalP == NULL)
    5876          488 :             cursorOptions |= CURSOR_OPT_PARALLEL_OK;
    5877          684 :         exec_prepare_plan(estate, expr, cursorOptions);
    5878              :     }
    5879              : 
    5880              :     /*
    5881              :      * Set up ParamListInfo to pass to executor
    5882              :      */
    5883        10824 :     paramLI = setup_param_list(estate, expr);
    5884              : 
    5885              :     /*
    5886              :      * If a portal was requested, put the query and paramlist into the portal
    5887              :      */
    5888        10824 :     if (portalP != NULL)
    5889              :     {
    5890         3256 :         *portalP = SPI_cursor_open_with_paramlist(NULL, expr->plan,
    5891              :                                                   paramLI,
    5892         1628 :                                                   estate->readonly_func);
    5893         1628 :         if (*portalP == NULL)
    5894            0 :             elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
    5895              :                  expr->query, SPI_result_code_string(SPI_result));
    5896         1628 :         exec_eval_cleanup(estate);
    5897         1628 :         return SPI_OK_CURSOR;
    5898              :     }
    5899              : 
    5900              :     /*
    5901              :      * Execute the query
    5902              :      */
    5903         9196 :     rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
    5904         9196 :                                          estate->readonly_func, maxtuples);
    5905         8217 :     if (rc != SPI_OK_SELECT)
    5906              :     {
    5907              :         /*
    5908              :          * SELECT INTO deserves a special error message, because "query is not
    5909              :          * a SELECT" is not very helpful in that case.
    5910              :          */
    5911            0 :         if (rc == SPI_OK_SELINTO)
    5912            0 :             ereport(ERROR,
    5913              :                     (errcode(ERRCODE_SYNTAX_ERROR),
    5914              :                      errmsg("query is SELECT INTO, but it should be plain SELECT"),
    5915              :                      errcontext("query: %s", expr->query)));
    5916              :         else
    5917            0 :             ereport(ERROR,
    5918              :                     (errcode(ERRCODE_SYNTAX_ERROR),
    5919              :                      errmsg("query is not a SELECT"),
    5920              :                      errcontext("query: %s", expr->query)));
    5921              :     }
    5922              : 
    5923              :     /* Save query results for eventual cleanup */
    5924              :     Assert(estate->eval_tuptable == NULL);
    5925         8217 :     estate->eval_tuptable = SPI_tuptable;
    5926         8217 :     estate->eval_processed = SPI_processed;
    5927              : 
    5928         8217 :     return rc;
    5929              : }
    5930              : 
    5931              : 
    5932              : /*
    5933              :  * exec_for_query --- execute body of FOR loop for each row from a portal
    5934              :  *
    5935              :  * Used by exec_stmt_fors, exec_stmt_forc and exec_stmt_dynfors
    5936              :  */
    5937              : static int
    5938         8084 : exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
    5939              :                Portal portal, bool prefetch_ok)
    5940              : {
    5941              :     PLpgSQL_variable *var;
    5942              :     SPITupleTable *tuptab;
    5943         8084 :     bool        found = false;
    5944         8084 :     int         rc = PLPGSQL_RC_OK;
    5945         8084 :     uint64      previous_id = INVALID_TUPLEDESC_IDENTIFIER;
    5946         8084 :     bool        tupdescs_match = true;
    5947              :     uint64      n;
    5948              : 
    5949              :     /* Fetch loop variable's datum entry */
    5950         8084 :     var = (PLpgSQL_variable *) estate->datums[stmt->var->dno];
    5951              : 
    5952              :     /*
    5953              :      * Make sure the portal doesn't get closed by the user statements we
    5954              :      * execute.
    5955              :      */
    5956         8084 :     PinPortal(portal);
    5957              : 
    5958              :     /*
    5959              :      * In a non-atomic context, we dare not prefetch, even if it would
    5960              :      * otherwise be safe.  Aside from any semantic hazards that that might
    5961              :      * create, if we prefetch toasted data and then the user commits the
    5962              :      * transaction, the toast references could turn into dangling pointers.
    5963              :      * (Rows we haven't yet fetched from the cursor are safe, because the
    5964              :      * PersistHoldablePortal mechanism handles this scenario.)
    5965              :      */
    5966         8084 :     if (!estate->atomic)
    5967         5022 :         prefetch_ok = false;
    5968              : 
    5969              :     /*
    5970              :      * Fetch the initial tuple(s).  If prefetching is allowed then we grab a
    5971              :      * few more rows to avoid multiple trips through executor startup
    5972              :      * overhead.
    5973              :      */
    5974         8084 :     SPI_cursor_fetch(portal, true, prefetch_ok ? 10 : 1);
    5975         8080 :     tuptab = SPI_tuptable;
    5976         8080 :     n = SPI_processed;
    5977              : 
    5978              :     /*
    5979              :      * If the query didn't return any rows, set the target to NULL and fall
    5980              :      * through with found = false.
    5981              :      */
    5982         8080 :     if (n == 0)
    5983              :     {
    5984         1147 :         exec_move_row(estate, var, NULL, tuptab->tupdesc);
    5985         1147 :         exec_eval_cleanup(estate);
    5986              :     }
    5987              :     else
    5988         6933 :         found = true;           /* processed at least one tuple */
    5989              : 
    5990              :     /*
    5991              :      * Now do the loop
    5992              :      */
    5993        29306 :     while (n > 0)
    5994              :     {
    5995              :         uint64      i;
    5996              : 
    5997        56911 :         for (i = 0; i < n; i++)
    5998              :         {
    5999              :             /*
    6000              :              * Assign the tuple to the target.  Here, because we know that all
    6001              :              * loop iterations should be assigning the same tupdesc, we can
    6002              :              * optimize away repeated creations of expanded records with
    6003              :              * identical tupdescs.  Testing for changes of er_tupdesc_id is
    6004              :              * reliable even if the loop body contains assignments that
    6005              :              * replace the target's value entirely, because it's assigned from
    6006              :              * a process-global counter.  The case where the tupdescs don't
    6007              :              * match could possibly be handled more efficiently than this
    6008              :              * coding does, but it's not clear extra effort is worthwhile.
    6009              :              */
    6010        35685 :             if (var->dtype == PLPGSQL_DTYPE_REC)
    6011              :             {
    6012         4575 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) var;
    6013              : 
    6014         4575 :                 if (rec->erh &&
    6015         4021 :                     rec->erh->er_tupdesc_id == previous_id &&
    6016              :                     tupdescs_match)
    6017              :                 {
    6018              :                     /* Only need to assign a new tuple value */
    6019         3975 :                     expanded_record_set_tuple(rec->erh, tuptab->vals[i],
    6020         3975 :                                               true, !estate->atomic);
    6021              :                 }
    6022              :                 else
    6023              :                 {
    6024              :                     /*
    6025              :                      * First time through, or var's tupdesc changed in loop,
    6026              :                      * or we have to do it the hard way because type coercion
    6027              :                      * is needed.
    6028              :                      */
    6029          600 :                     exec_move_row(estate, var,
    6030          600 :                                   tuptab->vals[i], tuptab->tupdesc);
    6031              : 
    6032              :                     /*
    6033              :                      * Check to see if physical assignment is OK next time.
    6034              :                      * Once the tupdesc comparison has failed once, we don't
    6035              :                      * bother rechecking in subsequent loop iterations.
    6036              :                      */
    6037          599 :                     if (tupdescs_match)
    6038              :                     {
    6039          595 :                         tupdescs_match =
    6040          607 :                             (rec->rectypeid == RECORDOID ||
    6041          607 :                              rec->rectypeid == tuptab->tupdesc->tdtypeid ||
    6042           12 :                              compatible_tupdescs(tuptab->tupdesc,
    6043              :                                                  expanded_record_get_tupdesc(rec->erh)));
    6044              :                     }
    6045          599 :                     previous_id = rec->erh->er_tupdesc_id;
    6046              :                 }
    6047              :             }
    6048              :             else
    6049        31110 :                 exec_move_row(estate, var, tuptab->vals[i], tuptab->tupdesc);
    6050              : 
    6051        35683 :             exec_eval_cleanup(estate);
    6052              : 
    6053              :             /*
    6054              :              * Execute the statements
    6055              :              */
    6056        35683 :             rc = exec_stmts(estate, stmt->body);
    6057              : 
    6058        35665 :             LOOP_RC_PROCESSING(stmt->label, goto loop_exit);
    6059              :         }
    6060              : 
    6061        21226 :         SPI_freetuptable(tuptab);
    6062              : 
    6063              :         /*
    6064              :          * Fetch more tuples.  If prefetching is allowed, grab 50 at a time.
    6065              :          */
    6066        21226 :         SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
    6067        21226 :         tuptab = SPI_tuptable;
    6068        21226 :         n = SPI_processed;
    6069              :     }
    6070              : 
    6071         7812 : loop_exit:
    6072              : 
    6073              :     /*
    6074              :      * Release last group of tuples (if any)
    6075              :      */
    6076         8060 :     SPI_freetuptable(tuptab);
    6077              : 
    6078         8060 :     UnpinPortal(portal);
    6079              : 
    6080              :     /*
    6081              :      * Set the FOUND variable to indicate the result of executing the loop
    6082              :      * (namely, whether we looped one or more times). This must be set last so
    6083              :      * that it does not interfere with the value of the FOUND variable inside
    6084              :      * the loop processing itself.
    6085              :      */
    6086         8060 :     exec_set_found(estate, found);
    6087              : 
    6088         8060 :     return rc;
    6089              : }
    6090              : 
    6091              : 
    6092              : /* ----------
    6093              :  * exec_eval_simple_expr -      Evaluate a simple expression returning
    6094              :  *                              a Datum by directly calling ExecEvalExpr().
    6095              :  *
    6096              :  * If successful, store results into *result, *isNull, *rettype, *rettypmod
    6097              :  * and return true.  If the expression cannot be handled by simple evaluation,
    6098              :  * return false.
    6099              :  *
    6100              :  * Because we only store one execution tree for a simple expression, we
    6101              :  * can't handle recursion cases.  So, if we see the tree is already busy
    6102              :  * with an evaluation in the current xact, we just return false and let the
    6103              :  * caller run the expression the hard way.  (Other alternatives such as
    6104              :  * creating a new tree for a recursive call either introduce memory leaks,
    6105              :  * or add enough bookkeeping to be doubtful wins anyway.)  Another case that
    6106              :  * is covered by the expr_simple_in_use test is where a previous execution
    6107              :  * of the tree was aborted by an error: the tree may contain bogus state
    6108              :  * so we dare not re-use it.
    6109              :  *
    6110              :  * It is possible that we'd need to replan a simple expression; for example,
    6111              :  * someone might redefine a SQL function that had been inlined into the simple
    6112              :  * expression.  That cannot cause a simple expression to become non-simple (or
    6113              :  * vice versa), but we do have to handle replacing the expression tree.
    6114              :  *
    6115              :  * Note: if pass-by-reference, the result is in the eval_mcontext.
    6116              :  * It will be freed when exec_eval_cleanup is done.
    6117              :  * ----------
    6118              :  */
    6119              : static bool
    6120       218686 : exec_eval_simple_expr(PLpgSQL_execstate *estate,
    6121              :                       PLpgSQL_expr *expr,
    6122              :                       Datum *result,
    6123              :                       bool *isNull,
    6124              :                       Oid *rettype,
    6125              :                       int32 *rettypmod)
    6126              : {
    6127       218686 :     ExprContext *econtext = estate->eval_econtext;
    6128       218686 :     LocalTransactionId curlxid = MyProc->vxid.lxid;
    6129              :     ParamListInfo paramLI;
    6130              :     void       *save_setup_arg;
    6131              :     bool        need_snapshot;
    6132              :     MemoryContext oldcontext;
    6133              : 
    6134              :     /*
    6135              :      * Forget it if expression wasn't simple before.
    6136              :      */
    6137       218686 :     if (expr->expr_simple_expr == NULL)
    6138         4936 :         return false;
    6139              : 
    6140              :     /*
    6141              :      * If expression is in use in current xact, don't touch it.
    6142              :      */
    6143       213750 :     if (unlikely(expr->expr_simple_in_use) &&
    6144          417 :         expr->expr_simple_lxid == curlxid)
    6145          373 :         return false;
    6146              : 
    6147              :     /*
    6148              :      * Ensure that there's a portal-level snapshot, in case this simple
    6149              :      * expression is the first thing evaluated after a COMMIT or ROLLBACK.
    6150              :      * We'd have to do this anyway before executing the expression, so we
    6151              :      * might as well do it now to ensure that any possible replanning doesn't
    6152              :      * need to take a new snapshot.
    6153              :      */
    6154       213377 :     EnsurePortalSnapshotExists();
    6155              : 
    6156              :     /*
    6157              :      * Check to see if the cached plan has been invalidated.  If not, and this
    6158              :      * is the first use in the current transaction, save a plan refcount in
    6159              :      * the simple-expression resowner.
    6160              :      */
    6161       213377 :     if (likely(CachedPlanIsSimplyValid(expr->expr_simple_plansource,
    6162              :                                        expr->expr_simple_plan,
    6163              :                                        (expr->expr_simple_plan_lxid != curlxid ?
    6164              :                                         estate->simple_eval_resowner : NULL))))
    6165              :     {
    6166              :         /*
    6167              :          * It's still good, so just remember that we have a refcount on the
    6168              :          * plan in the current transaction.  (If we already had one, this
    6169              :          * assignment is a no-op.)
    6170              :          */
    6171       209784 :         expr->expr_simple_plan_lxid = curlxid;
    6172              :     }
    6173              :     else
    6174              :     {
    6175              :         /* Need to replan */
    6176              :         CachedPlan *cplan;
    6177              : 
    6178              :         /*
    6179              :          * If we have a valid refcount on some previous version of the plan,
    6180              :          * release it, so we don't leak plans intra-transaction.
    6181              :          */
    6182         3593 :         if (expr->expr_simple_plan_lxid == curlxid)
    6183         1622 :             ReleaseCachedPlan(expr->expr_simple_plan,
    6184              :                               estate->simple_eval_resowner);
    6185              : 
    6186              :         /*
    6187              :          * Reset to "not simple" to leave sane state (with no dangling
    6188              :          * pointers) in case we fail while replanning.  We'll need to
    6189              :          * re-determine simplicity and R/W optimizability anyway, since those
    6190              :          * could change with the new plan.  expr_simple_plansource can be left
    6191              :          * alone however, as that cannot move.
    6192              :          */
    6193         3593 :         expr->expr_simple_expr = NULL;
    6194         3593 :         expr->expr_rwopt = PLPGSQL_RWOPT_UNKNOWN;
    6195         3593 :         expr->expr_rw_param = NULL;
    6196         3593 :         expr->expr_simple_plan = NULL;
    6197         3593 :         expr->expr_simple_plan_lxid = InvalidLocalTransactionId;
    6198              : 
    6199              :         /* Do the replanning work in the eval_mcontext */
    6200         3593 :         oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    6201         3593 :         cplan = SPI_plan_get_cached_plan(expr->plan);
    6202         3593 :         MemoryContextSwitchTo(oldcontext);
    6203              : 
    6204              :         /*
    6205              :          * We can't get a failure here, because the number of
    6206              :          * CachedPlanSources in the SPI plan can't change from what
    6207              :          * exec_simple_check_plan saw; it's a property of the raw parsetree
    6208              :          * generated from the query text.
    6209              :          */
    6210              :         Assert(cplan != NULL);
    6211              : 
    6212              :         /*
    6213              :          * Recheck exec_is_simple_query, which could now report false in
    6214              :          * edge-case scenarios such as a non-SRF having been replaced with a
    6215              :          * SRF.  Also recheck CachedPlanAllowsSimpleValidityCheck, just to be
    6216              :          * sure.  If either test fails, cope by declaring the plan to be
    6217              :          * non-simple.  On success, we'll acquire a refcount on the new plan,
    6218              :          * stored in simple_eval_resowner.
    6219              :          */
    6220         7185 :         if (exec_is_simple_query(expr) &&
    6221         3592 :             CachedPlanAllowsSimpleValidityCheck(expr->expr_simple_plansource,
    6222              :                                                 cplan,
    6223              :                                                 estate->simple_eval_resowner))
    6224              :         {
    6225              :             /* Remember that we have the refcount */
    6226         3592 :             expr->expr_simple_plan = cplan;
    6227         3592 :             expr->expr_simple_plan_lxid = curlxid;
    6228              :         }
    6229              :         else
    6230              :         {
    6231              :             /* Release SPI_plan_get_cached_plan's refcount */
    6232            1 :             ReleaseCachedPlan(cplan, CurrentResourceOwner);
    6233            1 :             return false;
    6234              :         }
    6235              : 
    6236              :         /*
    6237              :          * SPI_plan_get_cached_plan acquired a plan refcount stored in the
    6238              :          * active resowner.  We don't need that anymore, so release it.
    6239              :          */
    6240         3592 :         ReleaseCachedPlan(cplan, CurrentResourceOwner);
    6241              : 
    6242              :         /* Extract desired scalar expression from cached plan */
    6243         3592 :         exec_save_simple_expr(expr, cplan);
    6244              :     }
    6245              : 
    6246              :     /*
    6247              :      * Pass back previously-determined result type.
    6248              :      */
    6249       213376 :     *rettype = expr->expr_simple_type;
    6250       213376 :     *rettypmod = expr->expr_simple_typmod;
    6251              : 
    6252              :     /*
    6253              :      * Set up ParamListInfo to pass to executor.  For safety, save and restore
    6254              :      * estate->paramLI->parserSetupArg around our use of the param list.
    6255              :      */
    6256       213376 :     paramLI = estate->paramLI;
    6257       213376 :     save_setup_arg = paramLI->parserSetupArg;
    6258              : 
    6259              :     /*
    6260              :      * We can skip using setup_param_list() in favor of just doing this
    6261              :      * unconditionally, because there's no need for the optimization of
    6262              :      * possibly setting ecxt_param_list_info to NULL; we've already forced use
    6263              :      * of a generic plan.
    6264              :      */
    6265       213376 :     paramLI->parserSetupArg = expr;
    6266       213376 :     econtext->ecxt_param_list_info = paramLI;
    6267              : 
    6268              :     /*
    6269              :      * Prepare the expression for execution, if it's not been done already in
    6270              :      * the current transaction.  (This will be forced to happen if we called
    6271              :      * exec_save_simple_expr above.)
    6272              :      */
    6273       213376 :     if (unlikely(expr->expr_simple_lxid != curlxid))
    6274              :     {
    6275        53092 :         oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
    6276        53092 :         expr->expr_simple_state =
    6277        53092 :             ExecInitExprWithParams(expr->expr_simple_expr,
    6278              :                                    econtext->ecxt_param_list_info);
    6279        53092 :         expr->expr_simple_in_use = false;
    6280        53092 :         expr->expr_simple_lxid = curlxid;
    6281        53092 :         MemoryContextSwitchTo(oldcontext);
    6282              :     }
    6283              : 
    6284              :     /*
    6285              :      * We have to do some of the things SPI_execute_plan would do, in
    6286              :      * particular push a new snapshot so that stable functions within the
    6287              :      * expression can see updates made so far by our own function.  However,
    6288              :      * we can skip doing that (and just invoke the expression with the same
    6289              :      * snapshot passed to our function) in some cases, which is useful because
    6290              :      * it's quite expensive relative to the cost of a simple expression.  We
    6291              :      * can skip it if the expression contains no stable or volatile functions;
    6292              :      * immutable functions shouldn't need to see our updates.  Also, if this
    6293              :      * is a read-only function, we haven't made any updates so again it's okay
    6294              :      * to skip.
    6295              :      */
    6296       213376 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    6297       213376 :     need_snapshot = (expr->expr_simple_mutable && !estate->readonly_func);
    6298       213376 :     if (need_snapshot)
    6299              :     {
    6300        22930 :         CommandCounterIncrement();
    6301        22930 :         PushActiveSnapshot(GetTransactionSnapshot());
    6302              :     }
    6303              : 
    6304              :     /*
    6305              :      * Mark expression as busy for the duration of the ExecEvalExpr call.
    6306              :      */
    6307       213376 :     expr->expr_simple_in_use = true;
    6308              : 
    6309              :     /*
    6310              :      * Finally we can call the executor to evaluate the expression
    6311              :      */
    6312       213376 :     *result = ExecEvalExpr(expr->expr_simple_state,
    6313              :                            econtext,
    6314              :                            isNull);
    6315              : 
    6316              :     /* Assorted cleanup */
    6317       213218 :     expr->expr_simple_in_use = false;
    6318              : 
    6319       213218 :     econtext->ecxt_param_list_info = NULL;
    6320              : 
    6321       213218 :     paramLI->parserSetupArg = save_setup_arg;
    6322              : 
    6323       213218 :     if (need_snapshot)
    6324        22898 :         PopActiveSnapshot();
    6325              : 
    6326       213218 :     MemoryContextSwitchTo(oldcontext);
    6327              : 
    6328              :     /*
    6329              :      * That's it.
    6330              :      */
    6331       213218 :     return true;
    6332              : }
    6333              : 
    6334              : 
    6335              : /*
    6336              :  * Create a ParamListInfo to pass to SPI
    6337              :  *
    6338              :  * We use a single ParamListInfo struct for all SPI calls made to evaluate
    6339              :  * PLpgSQL_exprs in this estate.  It contains no per-param data, just hook
    6340              :  * functions, so it's effectively read-only for SPI.
    6341              :  *
    6342              :  * An exception from pure read-only-ness is that the parserSetupArg points
    6343              :  * to the specific PLpgSQL_expr being evaluated.  This is not an issue for
    6344              :  * statement-level callers, but lower-level callers must save and restore
    6345              :  * estate->paramLI->parserSetupArg just in case there's an active evaluation
    6346              :  * at an outer call level.  (A plausible alternative design would be to
    6347              :  * create a ParamListInfo struct for each PLpgSQL_expr, but for the moment
    6348              :  * that seems like a waste of memory.)
    6349              :  */
    6350              : static ParamListInfo
    6351        51942 : setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
    6352              : {
    6353              :     ParamListInfo paramLI;
    6354              : 
    6355              :     /*
    6356              :      * We must have created the SPIPlan already (hence, query text has been
    6357              :      * parsed/analyzed at least once); else we cannot rely on expr->paramnos.
    6358              :      */
    6359              :     Assert(expr->plan != NULL);
    6360              : 
    6361              :     /*
    6362              :      * We only need a ParamListInfo if the expression has parameters.
    6363              :      */
    6364        51942 :     if (!bms_is_empty(expr->paramnos))
    6365              :     {
    6366              :         /* Use the common ParamListInfo */
    6367        22185 :         paramLI = estate->paramLI;
    6368              : 
    6369              :         /*
    6370              :          * Set up link to active expr where the hook functions can find it.
    6371              :          * Callers must save and restore parserSetupArg if there is any chance
    6372              :          * that they are interrupting an active use of parameters.
    6373              :          */
    6374        22185 :         paramLI->parserSetupArg = expr;
    6375              :     }
    6376              :     else
    6377              :     {
    6378              :         /*
    6379              :          * Expression requires no parameters.  Be sure we represent this case
    6380              :          * as a NULL ParamListInfo, so that plancache.c knows there is no
    6381              :          * point in a custom plan.
    6382              :          */
    6383        29757 :         paramLI = NULL;
    6384              :     }
    6385        51942 :     return paramLI;
    6386              : }
    6387              : 
    6388              : /*
    6389              :  * plpgsql_param_fetch      paramFetch callback for dynamic parameter fetch
    6390              :  *
    6391              :  * We always use the caller's workspace to construct the returned struct.
    6392              :  *
    6393              :  * Note: this is no longer used during query execution.  It is used during
    6394              :  * planning (with speculative == true) and when the ParamListInfo we supply
    6395              :  * to the executor is copied into a cursor portal or transferred to a
    6396              :  * parallel child process.
    6397              :  */
    6398              : static ParamExternData *
    6399         7102 : plpgsql_param_fetch(ParamListInfo params,
    6400              :                     int paramid, bool speculative,
    6401              :                     ParamExternData *prm)
    6402              : {
    6403              :     int         dno;
    6404              :     PLpgSQL_execstate *estate;
    6405              :     PLpgSQL_expr *expr;
    6406              :     PLpgSQL_datum *datum;
    6407         7102 :     bool        ok = true;
    6408              :     int32       prmtypmod;
    6409              : 
    6410              :     /* paramid's are 1-based, but dnos are 0-based */
    6411         7102 :     dno = paramid - 1;
    6412              :     Assert(dno >= 0 && dno < params->numParams);
    6413              : 
    6414              :     /* fetch back the hook data */
    6415         7102 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6416         7102 :     expr = (PLpgSQL_expr *) params->parserSetupArg;
    6417              :     Assert(params->numParams == estate->ndatums);
    6418              : 
    6419              :     /* now we can access the target datum */
    6420         7102 :     datum = estate->datums[dno];
    6421              : 
    6422              :     /*
    6423              :      * Since copyParamList() or SerializeParamList() will try to materialize
    6424              :      * every single parameter slot, it's important to return a dummy param
    6425              :      * when asked for a datum that's not supposed to be used by this SQL
    6426              :      * expression.  Otherwise we risk failures in exec_eval_datum(), or
    6427              :      * copying a lot more data than necessary.
    6428              :      */
    6429         7102 :     if (!bms_is_member(dno, expr->paramnos))
    6430         2205 :         ok = false;
    6431              : 
    6432              :     /*
    6433              :      * If the access is speculative, we prefer to return no data rather than
    6434              :      * to fail in exec_eval_datum().  Check the likely failure cases.
    6435              :      */
    6436         4897 :     else if (speculative)
    6437              :     {
    6438         4236 :         switch (datum->dtype)
    6439              :         {
    6440         2421 :             case PLPGSQL_DTYPE_VAR:
    6441              :             case PLPGSQL_DTYPE_PROMISE:
    6442              :                 /* always safe */
    6443         2421 :                 break;
    6444              : 
    6445            0 :             case PLPGSQL_DTYPE_ROW:
    6446              :                 /* should be safe in all interesting cases */
    6447            0 :                 break;
    6448              : 
    6449          304 :             case PLPGSQL_DTYPE_REC:
    6450              :                 /* always safe (might return NULL, that's fine) */
    6451          304 :                 break;
    6452              : 
    6453         1511 :             case PLPGSQL_DTYPE_RECFIELD:
    6454              :                 {
    6455         1511 :                     PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
    6456              :                     PLpgSQL_rec *rec;
    6457              : 
    6458         1511 :                     rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    6459              : 
    6460              :                     /*
    6461              :                      * If record variable is NULL, don't risk anything.
    6462              :                      */
    6463         1511 :                     if (rec->erh == NULL)
    6464            0 :                         ok = false;
    6465              : 
    6466              :                     /*
    6467              :                      * Look up the field's properties if we have not already,
    6468              :                      * or if the tuple descriptor ID changed since last time.
    6469              :                      */
    6470         1511 :                     else if (unlikely(recfield->rectupledescid != rec->erh->er_tupdesc_id))
    6471              :                     {
    6472           11 :                         if (expanded_record_lookup_field(rec->erh,
    6473           11 :                                                          recfield->fieldname,
    6474              :                                                          &recfield->finfo))
    6475           11 :                             recfield->rectupledescid = rec->erh->er_tupdesc_id;
    6476              :                         else
    6477            0 :                             ok = false;
    6478              :                     }
    6479         1511 :                     break;
    6480              :                 }
    6481              : 
    6482            0 :             default:
    6483            0 :                 ok = false;
    6484            0 :                 break;
    6485              :         }
    6486              :     }
    6487              : 
    6488              :     /* Return "no such parameter" if not ok */
    6489         7102 :     if (!ok)
    6490              :     {
    6491         2205 :         prm->value = (Datum) 0;
    6492         2205 :         prm->isnull = true;
    6493         2205 :         prm->pflags = 0;
    6494         2205 :         prm->ptype = InvalidOid;
    6495         2205 :         return prm;
    6496              :     }
    6497              : 
    6498              :     /* OK, evaluate the value and store into the return struct */
    6499         4897 :     exec_eval_datum(estate, datum,
    6500              :                     &prm->ptype, &prmtypmod,
    6501              :                     &prm->value, &prm->isnull);
    6502              :     /* We can always mark params as "const" for executor's purposes */
    6503         4897 :     prm->pflags = PARAM_FLAG_CONST;
    6504              : 
    6505              :     /*
    6506              :      * If it's a read/write expanded datum, convert reference to read-only.
    6507              :      * (There's little point in trying to optimize read/write parameters,
    6508              :      * given the cases in which this function is used.)
    6509              :      */
    6510         4897 :     if (datum->dtype == PLPGSQL_DTYPE_VAR)
    6511         2915 :         prm->value = MakeExpandedObjectReadOnly(prm->value,
    6512              :                                                 prm->isnull,
    6513              :                                                 ((PLpgSQL_var *) datum)->datatype->typlen);
    6514         1982 :     else if (datum->dtype == PLPGSQL_DTYPE_REC)
    6515          304 :         prm->value = MakeExpandedObjectReadOnly(prm->value,
    6516              :                                                 prm->isnull,
    6517              :                                                 -1);
    6518              : 
    6519         4897 :     return prm;
    6520              : }
    6521              : 
    6522              : /*
    6523              :  * plpgsql_param_compile        paramCompile callback for plpgsql parameters
    6524              :  */
    6525              : static void
    6526        96349 : plpgsql_param_compile(ParamListInfo params, Param *param,
    6527              :                       ExprState *state,
    6528              :                       Datum *resv, bool *resnull)
    6529              : {
    6530              :     PLpgSQL_execstate *estate;
    6531              :     PLpgSQL_expr *expr;
    6532              :     int         dno;
    6533              :     PLpgSQL_datum *datum;
    6534              :     ExprEvalStep scratch;
    6535              : 
    6536              :     /* fetch back the hook data */
    6537        96349 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6538        96349 :     expr = (PLpgSQL_expr *) params->parserSetupArg;
    6539              : 
    6540              :     /* paramid's are 1-based, but dnos are 0-based */
    6541        96349 :     dno = param->paramid - 1;
    6542              :     Assert(dno >= 0 && dno < estate->ndatums);
    6543              : 
    6544              :     /* now we can access the target datum */
    6545        96349 :     datum = estate->datums[dno];
    6546              : 
    6547        96349 :     scratch.opcode = EEOP_PARAM_CALLBACK;
    6548        96349 :     scratch.resvalue = resv;
    6549        96349 :     scratch.resnull = resnull;
    6550              : 
    6551              :     /*
    6552              :      * Select appropriate eval function.
    6553              :      *
    6554              :      * First, if this Param references the same varlena-type DTYPE_VAR datum
    6555              :      * that is the target of the assignment containing this simple expression,
    6556              :      * then it's possible we will be able to optimize handling of R/W expanded
    6557              :      * datums.  We don't want to do the work needed to determine that unless
    6558              :      * we actually see a R/W expanded datum at runtime, so install a checking
    6559              :      * function that will figure that out when needed.
    6560              :      *
    6561              :      * Otherwise, it seems worth special-casing DTYPE_VAR and DTYPE_RECFIELD
    6562              :      * for performance.  Also, we can determine in advance whether
    6563              :      * MakeExpandedObjectReadOnly() will be required.  Currently, only
    6564              :      * VAR/PROMISE and REC datums could contain read/write expanded objects.
    6565              :      */
    6566        96349 :     if (datum->dtype == PLPGSQL_DTYPE_VAR)
    6567              :     {
    6568        61314 :         bool        isvarlena = (((PLpgSQL_var *) datum)->datatype->typlen == -1);
    6569              : 
    6570        61314 :         if (isvarlena && dno == expr->target_param && expr->expr_simple_expr)
    6571         1918 :             scratch.d.cparam.paramfunc = plpgsql_param_eval_var_check;
    6572        59396 :         else if (isvarlena)
    6573        45375 :             scratch.d.cparam.paramfunc = plpgsql_param_eval_var_ro;
    6574              :         else
    6575        14021 :             scratch.d.cparam.paramfunc = plpgsql_param_eval_var;
    6576              :     }
    6577        35035 :     else if (datum->dtype == PLPGSQL_DTYPE_RECFIELD)
    6578        17659 :         scratch.d.cparam.paramfunc = plpgsql_param_eval_recfield;
    6579        17376 :     else if (datum->dtype == PLPGSQL_DTYPE_PROMISE)
    6580              :     {
    6581        14761 :         if (((PLpgSQL_var *) datum)->datatype->typlen == -1)
    6582        12918 :             scratch.d.cparam.paramfunc = plpgsql_param_eval_generic_ro;
    6583              :         else
    6584         1843 :             scratch.d.cparam.paramfunc = plpgsql_param_eval_generic;
    6585              :     }
    6586         2615 :     else if (datum->dtype == PLPGSQL_DTYPE_REC)
    6587         2615 :         scratch.d.cparam.paramfunc = plpgsql_param_eval_generic_ro;
    6588              :     else
    6589            0 :         scratch.d.cparam.paramfunc = plpgsql_param_eval_generic;
    6590              : 
    6591              :     /*
    6592              :      * Note: it's tempting to use paramarg to store the estate pointer and
    6593              :      * thereby save an indirection or two in the eval functions.  But that
    6594              :      * doesn't work because the compiled expression might be used with
    6595              :      * different estates for the same PL/pgSQL function.  Instead, store
    6596              :      * pointers to the PLpgSQL_expr as well as this specific Param, to support
    6597              :      * plpgsql_param_eval_var_check().
    6598              :      */
    6599        96349 :     scratch.d.cparam.paramarg = expr;
    6600        96349 :     scratch.d.cparam.paramarg2 = param;
    6601        96349 :     scratch.d.cparam.paramid = param->paramid;
    6602        96349 :     scratch.d.cparam.paramtype = param->paramtype;
    6603        96349 :     ExprEvalPushStep(state, &scratch);
    6604        96349 : }
    6605              : 
    6606              : /*
    6607              :  * plpgsql_param_eval_var_check     evaluation of EEOP_PARAM_CALLBACK step
    6608              :  *
    6609              :  * This is specialized to the case of DTYPE_VAR variables for which
    6610              :  * we may need to determine the applicability of a read/write optimization,
    6611              :  * but we've not done that yet.  The work to determine applicability will
    6612              :  * be done at most once (per construction of the PL/pgSQL function's cache
    6613              :  * entry) when we first see that the target variable's old value is a R/W
    6614              :  * expanded object.  If we never do see that, nothing is lost: the amount
    6615              :  * of work done by this function in that case is just about the same as
    6616              :  * what would be done by plpgsql_param_eval_var_ro, which is what we'd
    6617              :  * have used otherwise.
    6618              :  */
    6619              : static void
    6620        20980 : plpgsql_param_eval_var_check(ExprState *state, ExprEvalStep *op,
    6621              :                              ExprContext *econtext)
    6622              : {
    6623              :     ParamListInfo params;
    6624              :     PLpgSQL_execstate *estate;
    6625        20980 :     int         dno = op->d.cparam.paramid - 1;
    6626              :     PLpgSQL_var *var;
    6627              : 
    6628              :     /* fetch back the hook data */
    6629        20980 :     params = econtext->ecxt_param_list_info;
    6630        20980 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6631              :     Assert(dno >= 0 && dno < estate->ndatums);
    6632              : 
    6633              :     /* now we can access the target datum */
    6634        20980 :     var = (PLpgSQL_var *) estate->datums[dno];
    6635              :     Assert(var->dtype == PLPGSQL_DTYPE_VAR);
    6636              : 
    6637              :     /*
    6638              :      * If the variable's current value is a R/W expanded object, it's time to
    6639              :      * decide whether/how to optimize the assignment.
    6640              :      */
    6641        41919 :     if (!var->isnull &&
    6642        20939 :         VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(var->value)))
    6643              :     {
    6644          106 :         PLpgSQL_expr *expr = (PLpgSQL_expr *) op->d.cparam.paramarg;
    6645          106 :         Param      *param = (Param *) op->d.cparam.paramarg2;
    6646              : 
    6647              :         /*
    6648              :          * We might have already figured this out while evaluating some other
    6649              :          * Param referencing the same variable, so check expr_rwopt first.
    6650              :          */
    6651          106 :         if (expr->expr_rwopt == PLPGSQL_RWOPT_UNKNOWN)
    6652           65 :             exec_check_rw_parameter(expr, op->d.cparam.paramid);
    6653              : 
    6654              :         /*
    6655              :          * Update the callback pointer to match what we decided to do, so that
    6656              :          * this function will not be called again.  Then pass off this
    6657              :          * execution to the newly-selected function.
    6658              :          */
    6659          106 :         switch (expr->expr_rwopt)
    6660              :         {
    6661            0 :             case PLPGSQL_RWOPT_UNKNOWN:
    6662              :                 Assert(false);
    6663            0 :                 break;
    6664            2 :             case PLPGSQL_RWOPT_NOPE:
    6665              :                 /* Force the value to read-only in all future executions */
    6666            2 :                 op->d.cparam.paramfunc = plpgsql_param_eval_var_ro;
    6667            2 :                 plpgsql_param_eval_var_ro(state, op, econtext);
    6668            2 :                 break;
    6669           98 :             case PLPGSQL_RWOPT_TRANSFER:
    6670              :                 /* There can be only one matching Param in this case */
    6671              :                 Assert(param == expr->expr_rw_param);
    6672              :                 /* When the value is read/write, transfer to exec context */
    6673           98 :                 op->d.cparam.paramfunc = plpgsql_param_eval_var_transfer;
    6674           98 :                 plpgsql_param_eval_var_transfer(state, op, econtext);
    6675           98 :                 break;
    6676            6 :             case PLPGSQL_RWOPT_INPLACE:
    6677            6 :                 if (param == expr->expr_rw_param)
    6678              :                 {
    6679              :                     /* When the value is read/write, deliver it as-is */
    6680            3 :                     op->d.cparam.paramfunc = plpgsql_param_eval_var;
    6681            3 :                     plpgsql_param_eval_var(state, op, econtext);
    6682              :                 }
    6683              :                 else
    6684              :                 {
    6685              :                     /* Not the optimizable reference, so force to read-only */
    6686            3 :                     op->d.cparam.paramfunc = plpgsql_param_eval_var_ro;
    6687            3 :                     plpgsql_param_eval_var_ro(state, op, econtext);
    6688              :                 }
    6689            6 :                 break;
    6690              :         }
    6691          106 :         return;
    6692              :     }
    6693              : 
    6694              :     /*
    6695              :      * Otherwise, continue to postpone that decision, and execute an inlined
    6696              :      * version of exec_eval_datum().  Although this value could potentially
    6697              :      * need MakeExpandedObjectReadOnly, we know it doesn't right now.
    6698              :      */
    6699        20874 :     *op->resvalue = var->value;
    6700        20874 :     *op->resnull = var->isnull;
    6701              : 
    6702              :     /* safety check -- an assertion should be sufficient */
    6703              :     Assert(var->datatype->typoid == op->d.cparam.paramtype);
    6704              : }
    6705              : 
    6706              : /*
    6707              :  * plpgsql_param_eval_var_transfer      evaluation of EEOP_PARAM_CALLBACK step
    6708              :  *
    6709              :  * This is specialized to the case of DTYPE_VAR variables for which
    6710              :  * we have determined that a read/write expanded value can be handed off
    6711              :  * into execution of the expression (and then possibly returned to our
    6712              :  * function's ownership afterwards).  We have to test though, because the
    6713              :  * variable might not contain a read/write expanded value during this
    6714              :  * execution.
    6715              :  */
    6716              : static void
    6717          150 : plpgsql_param_eval_var_transfer(ExprState *state, ExprEvalStep *op,
    6718              :                                 ExprContext *econtext)
    6719              : {
    6720              :     ParamListInfo params;
    6721              :     PLpgSQL_execstate *estate;
    6722          150 :     int         dno = op->d.cparam.paramid - 1;
    6723              :     PLpgSQL_var *var;
    6724              : 
    6725              :     /* fetch back the hook data */
    6726          150 :     params = econtext->ecxt_param_list_info;
    6727          150 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6728              :     Assert(dno >= 0 && dno < estate->ndatums);
    6729              : 
    6730              :     /* now we can access the target datum */
    6731          150 :     var = (PLpgSQL_var *) estate->datums[dno];
    6732              :     Assert(var->dtype == PLPGSQL_DTYPE_VAR);
    6733              : 
    6734              :     /*
    6735              :      * If the variable's current value is a R/W expanded object, transfer its
    6736              :      * ownership into the expression execution context, then drop our own
    6737              :      * reference to the value by setting the variable to NULL.  That'll be
    6738              :      * overwritten (perhaps with this same object) when control comes back
    6739              :      * from the expression.
    6740              :      */
    6741          300 :     if (!var->isnull &&
    6742          150 :         VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(var->value)))
    6743              :     {
    6744          300 :         *op->resvalue = TransferExpandedObject(var->value,
    6745          150 :                                                get_eval_mcontext(estate));
    6746          150 :         *op->resnull = false;
    6747              : 
    6748          150 :         var->value = (Datum) 0;
    6749          150 :         var->isnull = true;
    6750          150 :         var->freeval = false;
    6751              :     }
    6752              :     else
    6753              :     {
    6754              :         /*
    6755              :          * Otherwise we can pass the variable's value directly; we now know
    6756              :          * that MakeExpandedObjectReadOnly isn't needed.
    6757              :          */
    6758            0 :         *op->resvalue = var->value;
    6759            0 :         *op->resnull = var->isnull;
    6760              :     }
    6761              : 
    6762              :     /* safety check -- an assertion should be sufficient */
    6763              :     Assert(var->datatype->typoid == op->d.cparam.paramtype);
    6764          150 : }
    6765              : 
    6766              : /*
    6767              :  * plpgsql_param_eval_var       evaluation of EEOP_PARAM_CALLBACK step
    6768              :  *
    6769              :  * This is specialized to the case of DTYPE_VAR variables for which
    6770              :  * we do not need to invoke MakeExpandedObjectReadOnly.
    6771              :  */
    6772              : static void
    6773        90025 : plpgsql_param_eval_var(ExprState *state, ExprEvalStep *op,
    6774              :                        ExprContext *econtext)
    6775              : {
    6776              :     ParamListInfo params;
    6777              :     PLpgSQL_execstate *estate;
    6778        90025 :     int         dno = op->d.cparam.paramid - 1;
    6779              :     PLpgSQL_var *var;
    6780              : 
    6781              :     /* fetch back the hook data */
    6782        90025 :     params = econtext->ecxt_param_list_info;
    6783        90025 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6784              :     Assert(dno >= 0 && dno < estate->ndatums);
    6785              : 
    6786              :     /* now we can access the target datum */
    6787        90025 :     var = (PLpgSQL_var *) estate->datums[dno];
    6788              :     Assert(var->dtype == PLPGSQL_DTYPE_VAR);
    6789              : 
    6790              :     /* inlined version of exec_eval_datum() */
    6791        90025 :     *op->resvalue = var->value;
    6792        90025 :     *op->resnull = var->isnull;
    6793              : 
    6794              :     /* safety check -- an assertion should be sufficient */
    6795              :     Assert(var->datatype->typoid == op->d.cparam.paramtype);
    6796        90025 : }
    6797              : 
    6798              : /*
    6799              :  * plpgsql_param_eval_var_ro        evaluation of EEOP_PARAM_CALLBACK step
    6800              :  *
    6801              :  * This is specialized to the case of DTYPE_VAR variables for which
    6802              :  * we need to invoke MakeExpandedObjectReadOnly.
    6803              :  */
    6804              : static void
    6805       104701 : plpgsql_param_eval_var_ro(ExprState *state, ExprEvalStep *op,
    6806              :                           ExprContext *econtext)
    6807              : {
    6808              :     ParamListInfo params;
    6809              :     PLpgSQL_execstate *estate;
    6810       104701 :     int         dno = op->d.cparam.paramid - 1;
    6811              :     PLpgSQL_var *var;
    6812              : 
    6813              :     /* fetch back the hook data */
    6814       104701 :     params = econtext->ecxt_param_list_info;
    6815       104701 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6816              :     Assert(dno >= 0 && dno < estate->ndatums);
    6817              : 
    6818              :     /* now we can access the target datum */
    6819       104701 :     var = (PLpgSQL_var *) estate->datums[dno];
    6820              :     Assert(var->dtype == PLPGSQL_DTYPE_VAR);
    6821              : 
    6822              :     /*
    6823              :      * Inlined version of exec_eval_datum() ... and while we're at it, force
    6824              :      * expanded datums to read-only.
    6825              :      */
    6826       104701 :     *op->resvalue = MakeExpandedObjectReadOnly(var->value,
    6827              :                                                var->isnull,
    6828              :                                                -1);
    6829       104701 :     *op->resnull = var->isnull;
    6830              : 
    6831              :     /* safety check -- an assertion should be sufficient */
    6832              :     Assert(var->datatype->typoid == op->d.cparam.paramtype);
    6833       104701 : }
    6834              : 
    6835              : /*
    6836              :  * plpgsql_param_eval_recfield      evaluation of EEOP_PARAM_CALLBACK step
    6837              :  *
    6838              :  * This is specialized to the case of DTYPE_RECFIELD variables, for which
    6839              :  * we never need to invoke MakeExpandedObjectReadOnly.
    6840              :  */
    6841              : static void
    6842        43910 : plpgsql_param_eval_recfield(ExprState *state, ExprEvalStep *op,
    6843              :                             ExprContext *econtext)
    6844              : {
    6845              :     ParamListInfo params;
    6846              :     PLpgSQL_execstate *estate;
    6847        43910 :     int         dno = op->d.cparam.paramid - 1;
    6848              :     PLpgSQL_recfield *recfield;
    6849              :     PLpgSQL_rec *rec;
    6850              :     ExpandedRecordHeader *erh;
    6851              : 
    6852              :     /* fetch back the hook data */
    6853        43910 :     params = econtext->ecxt_param_list_info;
    6854        43910 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6855              :     Assert(dno >= 0 && dno < estate->ndatums);
    6856              : 
    6857              :     /* now we can access the target datum */
    6858        43910 :     recfield = (PLpgSQL_recfield *) estate->datums[dno];
    6859              :     Assert(recfield->dtype == PLPGSQL_DTYPE_RECFIELD);
    6860              : 
    6861              :     /* inline the relevant part of exec_eval_datum */
    6862        43910 :     rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    6863        43910 :     erh = rec->erh;
    6864              : 
    6865              :     /*
    6866              :      * If record variable is NULL, instantiate it if it has a named composite
    6867              :      * type, else complain.  (This won't change the logical state of the
    6868              :      * record: it's still NULL.)
    6869              :      */
    6870        43910 :     if (erh == NULL)
    6871              :     {
    6872            1 :         instantiate_empty_record_variable(estate, rec);
    6873            1 :         erh = rec->erh;
    6874              :     }
    6875              : 
    6876              :     /*
    6877              :      * Look up the field's properties if we have not already, or if the tuple
    6878              :      * descriptor ID changed since last time.
    6879              :      */
    6880        43910 :     if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
    6881              :     {
    6882         2615 :         if (!expanded_record_lookup_field(erh,
    6883         2615 :                                           recfield->fieldname,
    6884              :                                           &recfield->finfo))
    6885            1 :             ereport(ERROR,
    6886              :                     (errcode(ERRCODE_UNDEFINED_COLUMN),
    6887              :                      errmsg("record \"%s\" has no field \"%s\"",
    6888              :                             rec->refname, recfield->fieldname)));
    6889         2614 :         recfield->rectupledescid = erh->er_tupdesc_id;
    6890              :     }
    6891              : 
    6892              :     /* OK to fetch the field value. */
    6893        43909 :     *op->resvalue = expanded_record_get_field(erh,
    6894              :                                               recfield->finfo.fnumber,
    6895              :                                               op->resnull);
    6896              : 
    6897              :     /* safety check -- needed for, eg, record fields */
    6898        43909 :     if (unlikely(recfield->finfo.ftypeid != op->d.cparam.paramtype))
    6899            2 :         ereport(ERROR,
    6900              :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    6901              :                  errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
    6902              :                         op->d.cparam.paramid,
    6903              :                         format_type_be(recfield->finfo.ftypeid),
    6904              :                         format_type_be(op->d.cparam.paramtype))));
    6905        43907 : }
    6906              : 
    6907              : /*
    6908              :  * plpgsql_param_eval_generic       evaluation of EEOP_PARAM_CALLBACK step
    6909              :  *
    6910              :  * This handles all variable types, but assumes we do not need to invoke
    6911              :  * MakeExpandedObjectReadOnly.
    6912              :  */
    6913              : static void
    6914         2095 : plpgsql_param_eval_generic(ExprState *state, ExprEvalStep *op,
    6915              :                            ExprContext *econtext)
    6916              : {
    6917              :     ParamListInfo params;
    6918              :     PLpgSQL_execstate *estate;
    6919         2095 :     int         dno = op->d.cparam.paramid - 1;
    6920              :     PLpgSQL_datum *datum;
    6921              :     Oid         datumtype;
    6922              :     int32       datumtypmod;
    6923              : 
    6924              :     /* fetch back the hook data */
    6925         2095 :     params = econtext->ecxt_param_list_info;
    6926         2095 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6927              :     Assert(dno >= 0 && dno < estate->ndatums);
    6928              : 
    6929              :     /* now we can access the target datum */
    6930         2095 :     datum = estate->datums[dno];
    6931              : 
    6932              :     /* fetch datum's value */
    6933         2095 :     exec_eval_datum(estate, datum,
    6934              :                     &datumtype, &datumtypmod,
    6935              :                     op->resvalue, op->resnull);
    6936              : 
    6937              :     /* safety check -- needed for, eg, record fields */
    6938         2095 :     if (unlikely(datumtype != op->d.cparam.paramtype))
    6939            0 :         ereport(ERROR,
    6940              :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    6941              :                  errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
    6942              :                         op->d.cparam.paramid,
    6943              :                         format_type_be(datumtype),
    6944              :                         format_type_be(op->d.cparam.paramtype))));
    6945         2095 : }
    6946              : 
    6947              : /*
    6948              :  * plpgsql_param_eval_generic_ro    evaluation of EEOP_PARAM_CALLBACK step
    6949              :  *
    6950              :  * This handles all variable types, but assumes we need to invoke
    6951              :  * MakeExpandedObjectReadOnly (hence, variable must be of a varlena type).
    6952              :  */
    6953              : static void
    6954        16753 : plpgsql_param_eval_generic_ro(ExprState *state, ExprEvalStep *op,
    6955              :                               ExprContext *econtext)
    6956              : {
    6957              :     ParamListInfo params;
    6958              :     PLpgSQL_execstate *estate;
    6959        16753 :     int         dno = op->d.cparam.paramid - 1;
    6960              :     PLpgSQL_datum *datum;
    6961              :     Oid         datumtype;
    6962              :     int32       datumtypmod;
    6963              : 
    6964              :     /* fetch back the hook data */
    6965        16753 :     params = econtext->ecxt_param_list_info;
    6966        16753 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6967              :     Assert(dno >= 0 && dno < estate->ndatums);
    6968              : 
    6969              :     /* now we can access the target datum */
    6970        16753 :     datum = estate->datums[dno];
    6971              : 
    6972              :     /* fetch datum's value */
    6973        16753 :     exec_eval_datum(estate, datum,
    6974              :                     &datumtype, &datumtypmod,
    6975              :                     op->resvalue, op->resnull);
    6976              : 
    6977              :     /* safety check -- needed for, eg, record fields */
    6978        16753 :     if (unlikely(datumtype != op->d.cparam.paramtype))
    6979            0 :         ereport(ERROR,
    6980              :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    6981              :                  errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
    6982              :                         op->d.cparam.paramid,
    6983              :                         format_type_be(datumtype),
    6984              :                         format_type_be(op->d.cparam.paramtype))));
    6985              : 
    6986              :     /* force the value to read-only */
    6987        16753 :     *op->resvalue = MakeExpandedObjectReadOnly(*op->resvalue,
    6988              :                                                *op->resnull,
    6989              :                                                -1);
    6990        16753 : }
    6991              : 
    6992              : 
    6993              : /*
    6994              :  * exec_move_row            Move one tuple's values into a record or row
    6995              :  *
    6996              :  * tup and tupdesc may both be NULL if we're just assigning an indeterminate
    6997              :  * composite NULL to the target.  Alternatively, can have tup be NULL and
    6998              :  * tupdesc not NULL, in which case we assign a row of NULLs to the target.
    6999              :  *
    7000              :  * Since this uses the mcontext for workspace, caller should eventually call
    7001              :  * exec_eval_cleanup to prevent long-term memory leaks.
    7002              :  */
    7003              : static void
    7004        47772 : exec_move_row(PLpgSQL_execstate *estate,
    7005              :               PLpgSQL_variable *target,
    7006              :               HeapTuple tup, TupleDesc tupdesc)
    7007              : {
    7008        47772 :     ExpandedRecordHeader *newerh = NULL;
    7009              : 
    7010              :     /*
    7011              :      * If target is RECORD, we may be able to avoid field-by-field processing.
    7012              :      */
    7013        47772 :     if (target->dtype == PLPGSQL_DTYPE_REC)
    7014              :     {
    7015         7015 :         PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
    7016              : 
    7017              :         /*
    7018              :          * If we have no source tupdesc, just set the record variable to NULL.
    7019              :          * (If we have a source tupdesc but not a tuple, we'll set the
    7020              :          * variable to a row of nulls, instead.  This is odd perhaps, but
    7021              :          * backwards compatible.)
    7022              :          */
    7023         7015 :         if (tupdesc == NULL)
    7024              :         {
    7025         3222 :             if (rec->datatype &&
    7026         3222 :                 rec->datatype->typtype == TYPTYPE_DOMAIN)
    7027              :             {
    7028              :                 /*
    7029              :                  * If it's a composite domain, NULL might not be a legal
    7030              :                  * value, so we instead need to make an empty expanded record
    7031              :                  * and ensure that domain type checking gets done.  If there
    7032              :                  * is already an expanded record, piggyback on its lookups.
    7033              :                  */
    7034           17 :                 newerh = make_expanded_record_for_rec(estate, rec,
    7035              :                                                       NULL, rec->erh);
    7036           17 :                 expanded_record_set_tuple(newerh, NULL, false, false);
    7037           13 :                 assign_record_var(estate, rec, newerh);
    7038              :             }
    7039              :             else
    7040              :             {
    7041              :                 /* Just clear it to NULL */
    7042         3205 :                 if (rec->erh)
    7043           81 :                     DeleteExpandedObject(ExpandedRecordGetDatum(rec->erh));
    7044         3205 :                 rec->erh = NULL;
    7045              :             }
    7046         3218 :             return;
    7047              :         }
    7048              : 
    7049              :         /*
    7050              :          * Build a new expanded record with appropriate tupdesc.
    7051              :          */
    7052         3793 :         newerh = make_expanded_record_for_rec(estate, rec, tupdesc, NULL);
    7053              : 
    7054              :         /*
    7055              :          * If the rowtypes match, or if we have no tuple anyway, we can
    7056              :          * complete the assignment without field-by-field processing.
    7057              :          *
    7058              :          * The tests here are ordered more or less in order of cheapness.  We
    7059              :          * can easily detect it will work if the target is declared RECORD or
    7060              :          * has the same typeid as the source.  But when assigning from a query
    7061              :          * result, it's common to have a source tupdesc that's labeled RECORD
    7062              :          * but is actually physically compatible with a named-composite-type
    7063              :          * target, so it's worth spending extra cycles to check for that.
    7064              :          */
    7065         3793 :         if (rec->rectypeid == RECORDOID ||
    7066          128 :             rec->rectypeid == tupdesc->tdtypeid ||
    7067          128 :             !HeapTupleIsValid(tup) ||
    7068          128 :             compatible_tupdescs(tupdesc, expanded_record_get_tupdesc(newerh)))
    7069              :         {
    7070         3740 :             if (!HeapTupleIsValid(tup))
    7071              :             {
    7072              :                 /* No data, so force the record into all-nulls state */
    7073         1083 :                 deconstruct_expanded_record(newerh);
    7074              :             }
    7075              :             else
    7076              :             {
    7077              :                 /* No coercion is needed, so just assign the row value */
    7078         2657 :                 expanded_record_set_tuple(newerh, tup, true, !estate->atomic);
    7079              :             }
    7080              : 
    7081              :             /* Complete the assignment */
    7082         3737 :             assign_record_var(estate, rec, newerh);
    7083              : 
    7084         3737 :             return;
    7085              :         }
    7086              :     }
    7087              : 
    7088              :     /*
    7089              :      * Otherwise, deconstruct the tuple and do field-by-field assignment,
    7090              :      * using exec_move_row_from_fields.
    7091              :      */
    7092        40810 :     if (tupdesc && HeapTupleIsValid(tup))
    7093        40664 :     {
    7094        40685 :         int         td_natts = tupdesc->natts;
    7095              :         Datum      *values;
    7096              :         bool       *nulls;
    7097              :         Datum       values_local[64];
    7098              :         bool        nulls_local[64];
    7099              : 
    7100              :         /*
    7101              :          * Need workspace arrays.  If td_natts is small enough, use local
    7102              :          * arrays to save doing a palloc.  Even if it's not small, we can
    7103              :          * allocate both the Datum and isnull arrays in one palloc chunk.
    7104              :          */
    7105        40685 :         if (td_natts <= lengthof(values_local))
    7106              :         {
    7107        40685 :             values = values_local;
    7108        40685 :             nulls = nulls_local;
    7109              :         }
    7110              :         else
    7111              :         {
    7112              :             char       *chunk;
    7113              : 
    7114            0 :             chunk = eval_mcontext_alloc(estate,
    7115              :                                         td_natts * (sizeof(Datum) + sizeof(bool)));
    7116            0 :             values = (Datum *) chunk;
    7117            0 :             nulls = (bool *) (chunk + td_natts * sizeof(Datum));
    7118              :         }
    7119              : 
    7120        40685 :         heap_deform_tuple(tup, tupdesc, values, nulls);
    7121              : 
    7122        40685 :         exec_move_row_from_fields(estate, target, newerh,
    7123              :                                   values, nulls, tupdesc);
    7124              :     }
    7125              :     else
    7126              :     {
    7127              :         /*
    7128              :          * Assign all-nulls.
    7129              :          */
    7130          125 :         exec_move_row_from_fields(estate, target, newerh,
    7131              :                                   NULL, NULL, NULL);
    7132              :     }
    7133              : }
    7134              : 
    7135              : /*
    7136              :  * Verify that a PLpgSQL_rec's rectypeid is up-to-date.
    7137              :  */
    7138              : static void
    7139          384 : revalidate_rectypeid(PLpgSQL_rec *rec)
    7140              : {
    7141          384 :     PLpgSQL_type *typ = rec->datatype;
    7142              :     TypeCacheEntry *typentry;
    7143              : 
    7144          384 :     if (rec->rectypeid == RECORDOID)
    7145          150 :         return;                 /* it's RECORD, so nothing to do */
    7146              :     Assert(typ != NULL);
    7147          234 :     if (typ->tcache &&
    7148          234 :         typ->tcache->tupDesc_identifier == typ->tupdesc_id)
    7149              :     {
    7150              :         /*
    7151              :          * Although *typ is known up-to-date, it's possible that rectypeid
    7152              :          * isn't, because *rec is cloned during each function startup from a
    7153              :          * copy that we don't have a good way to update.  Hence, forcibly fix
    7154              :          * rectypeid before returning.
    7155              :          */
    7156          228 :         rec->rectypeid = typ->typoid;
    7157          228 :         return;
    7158              :     }
    7159              : 
    7160              :     /*
    7161              :      * typcache entry has suffered invalidation, so re-look-up the type name
    7162              :      * if possible, and then recheck the type OID.  If we don't have a
    7163              :      * TypeName, then we just have to soldier on with the OID we've got.
    7164              :      */
    7165            6 :     if (typ->origtypname != NULL)
    7166              :     {
    7167              :         /* this bit should match parse_datatype() in pl_gram.y */
    7168            4 :         typenameTypeIdAndMod(NULL, typ->origtypname,
    7169              :                              &typ->typoid,
    7170              :                              &typ->atttypmod);
    7171              :     }
    7172              : 
    7173              :     /* this bit should match build_datatype() in pl_comp.c */
    7174            5 :     typentry = lookup_type_cache(typ->typoid,
    7175              :                                  TYPECACHE_TUPDESC |
    7176              :                                  TYPECACHE_DOMAIN_BASE_INFO);
    7177            5 :     if (typentry->typtype == TYPTYPE_DOMAIN)
    7178            0 :         typentry = lookup_type_cache(typentry->domainBaseType,
    7179              :                                      TYPECACHE_TUPDESC);
    7180            5 :     if (typentry->tupDesc == NULL)
    7181              :     {
    7182              :         /*
    7183              :          * If we get here, user tried to replace a composite type with a
    7184              :          * non-composite one.  We're not gonna support that.
    7185              :          */
    7186            0 :         ereport(ERROR,
    7187              :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
    7188              :                  errmsg("type %s is not composite",
    7189              :                         format_type_be(typ->typoid))));
    7190              :     }
    7191              : 
    7192              :     /*
    7193              :      * Update tcache and tupdesc_id.  Since we don't support changing to a
    7194              :      * non-composite type, none of the rest of *typ needs to change.
    7195              :      */
    7196            5 :     typ->tcache = typentry;
    7197            5 :     typ->tupdesc_id = typentry->tupDesc_identifier;
    7198              : 
    7199              :     /*
    7200              :      * Update *rec, too.  (We'll deal with subsidiary RECFIELDs as needed.)
    7201              :      */
    7202            5 :     rec->rectypeid = typ->typoid;
    7203              : }
    7204              : 
    7205              : /*
    7206              :  * Build an expanded record object suitable for assignment to "rec".
    7207              :  *
    7208              :  * Caller must supply either a source tuple descriptor or a source expanded
    7209              :  * record (not both).  If the record variable has declared type RECORD,
    7210              :  * it'll adopt the source's rowtype.  Even if it doesn't, we may be able to
    7211              :  * piggyback on a source expanded record to save a typcache lookup.
    7212              :  *
    7213              :  * Caller must fill the object with data, then do assign_record_var().
    7214              :  *
    7215              :  * The new record is initially put into the mcontext, so it will be cleaned up
    7216              :  * if we fail before reaching assign_record_var().
    7217              :  */
    7218              : static ExpandedRecordHeader *
    7219         3971 : make_expanded_record_for_rec(PLpgSQL_execstate *estate,
    7220              :                              PLpgSQL_rec *rec,
    7221              :                              TupleDesc srctupdesc,
    7222              :                              ExpandedRecordHeader *srcerh)
    7223              : {
    7224              :     ExpandedRecordHeader *newerh;
    7225         3971 :     MemoryContext mcontext = get_eval_mcontext(estate);
    7226              : 
    7227         3971 :     if (rec->rectypeid != RECORDOID)
    7228              :     {
    7229              :         /*
    7230              :          * Make sure rec->rectypeid is up-to-date before using it.
    7231              :          */
    7232          157 :         revalidate_rectypeid(rec);
    7233              : 
    7234              :         /*
    7235              :          * New record must be of desired type, but maybe srcerh has already
    7236              :          * done all the same lookups.
    7237              :          */
    7238          157 :         if (srcerh && rec->rectypeid == srcerh->er_decltypeid)
    7239           13 :             newerh = make_expanded_record_from_exprecord(srcerh,
    7240              :                                                          mcontext);
    7241              :         else
    7242          144 :             newerh = make_expanded_record_from_typeid(rec->rectypeid, -1,
    7243              :                                                       mcontext);
    7244              :     }
    7245              :     else
    7246              :     {
    7247              :         /*
    7248              :          * We'll adopt the input tupdesc.  We can still use
    7249              :          * make_expanded_record_from_exprecord, if srcerh isn't a composite
    7250              :          * domain.  (If it is, we effectively adopt its base type.)
    7251              :          */
    7252         3814 :         if (srcerh && !ExpandedRecordIsDomain(srcerh))
    7253          149 :             newerh = make_expanded_record_from_exprecord(srcerh,
    7254              :                                                          mcontext);
    7255              :         else
    7256              :         {
    7257         3665 :             if (!srctupdesc)
    7258            0 :                 srctupdesc = expanded_record_get_tupdesc(srcerh);
    7259         3665 :             newerh = make_expanded_record_from_tupdesc(srctupdesc,
    7260              :                                                        mcontext);
    7261              :         }
    7262              :     }
    7263              : 
    7264         3971 :     return newerh;
    7265              : }
    7266              : 
    7267              : /*
    7268              :  * exec_move_row_from_fields    Move arrays of field values into a record or row
    7269              :  *
    7270              :  * When assigning to a record, the caller must have already created a suitable
    7271              :  * new expanded record object, newerh.  Pass NULL when assigning to a row.
    7272              :  *
    7273              :  * tupdesc describes the input row, which might have different column
    7274              :  * types and/or different dropped-column positions than the target.
    7275              :  * values/nulls/tupdesc can all be NULL if we just want to assign nulls to
    7276              :  * all fields of the record or row.
    7277              :  *
    7278              :  * Since this uses the mcontext for workspace, caller should eventually call
    7279              :  * exec_eval_cleanup to prevent long-term memory leaks.
    7280              :  */
    7281              : static void
    7282        40820 : exec_move_row_from_fields(PLpgSQL_execstate *estate,
    7283              :                           PLpgSQL_variable *target,
    7284              :                           ExpandedRecordHeader *newerh,
    7285              :                           Datum *values, bool *nulls,
    7286              :                           TupleDesc tupdesc)
    7287              : {
    7288        40820 :     int         td_natts = tupdesc ? tupdesc->natts : 0;
    7289              :     int         fnum;
    7290              :     int         anum;
    7291        40820 :     int         strict_multiassignment_level = 0;
    7292              : 
    7293              :     /*
    7294              :      * The extra check strict strict_multi_assignment can be active, only when
    7295              :      * input tupdesc is specified.
    7296              :      */
    7297        40820 :     if (tupdesc != NULL)
    7298              :     {
    7299        40695 :         if (plpgsql_extra_errors & PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT)
    7300           24 :             strict_multiassignment_level = ERROR;
    7301        40671 :         else if (plpgsql_extra_warnings & PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT)
    7302           12 :             strict_multiassignment_level = WARNING;
    7303              :     }
    7304              : 
    7305              :     /* Handle RECORD-target case */
    7306        40820 :     if (target->dtype == PLPGSQL_DTYPE_REC)
    7307              :     {
    7308           63 :         PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
    7309              :         TupleDesc   var_tupdesc;
    7310              :         Datum       newvalues_local[64];
    7311              :         bool        newnulls_local[64];
    7312              : 
    7313              :         Assert(newerh != NULL); /* caller must have built new object */
    7314              : 
    7315           63 :         var_tupdesc = expanded_record_get_tupdesc(newerh);
    7316              : 
    7317              :         /*
    7318              :          * Coerce field values if needed.  This might involve dealing with
    7319              :          * different sets of dropped columns and/or coercing individual column
    7320              :          * types.  That's sort of a pain, but historically plpgsql has allowed
    7321              :          * it, so we preserve the behavior.  However, it's worth a quick check
    7322              :          * to see if the tupdescs are identical.  (Since expandedrecord.c
    7323              :          * prefers to use refcounted tupdescs from the typcache, expanded
    7324              :          * records with the same rowtype will have pointer-equal tupdescs.)
    7325              :          */
    7326           63 :         if (var_tupdesc != tupdesc)
    7327              :         {
    7328           56 :             int         vtd_natts = var_tupdesc->natts;
    7329              :             Datum      *newvalues;
    7330              :             bool       *newnulls;
    7331              : 
    7332              :             /*
    7333              :              * Need workspace arrays.  If vtd_natts is small enough, use local
    7334              :              * arrays to save doing a palloc.  Even if it's not small, we can
    7335              :              * allocate both the Datum and isnull arrays in one palloc chunk.
    7336              :              */
    7337           56 :             if (vtd_natts <= lengthof(newvalues_local))
    7338              :             {
    7339           56 :                 newvalues = newvalues_local;
    7340           56 :                 newnulls = newnulls_local;
    7341              :             }
    7342              :             else
    7343              :             {
    7344              :                 char       *chunk;
    7345              : 
    7346            0 :                 chunk = eval_mcontext_alloc(estate,
    7347              :                                             vtd_natts * (sizeof(Datum) + sizeof(bool)));
    7348            0 :                 newvalues = (Datum *) chunk;
    7349            0 :                 newnulls = (bool *) (chunk + vtd_natts * sizeof(Datum));
    7350              :             }
    7351              : 
    7352              :             /* Walk over destination columns */
    7353           56 :             anum = 0;
    7354          176 :             for (fnum = 0; fnum < vtd_natts; fnum++)
    7355              :             {
    7356          125 :                 Form_pg_attribute attr = TupleDescAttr(var_tupdesc, fnum);
    7357              :                 Datum       value;
    7358              :                 bool        isnull;
    7359              :                 Oid         valtype;
    7360              :                 int32       valtypmod;
    7361              : 
    7362          125 :                 if (attr->attisdropped)
    7363              :                 {
    7364              :                     /* expanded_record_set_fields should ignore this column */
    7365           13 :                     continue;   /* skip dropped column in record */
    7366              :                 }
    7367              : 
    7368          112 :                 while (anum < td_natts &&
    7369          108 :                        TupleDescAttr(tupdesc, anum)->attisdropped)
    7370            0 :                     anum++;     /* skip dropped column in tuple */
    7371              : 
    7372          112 :                 if (anum < td_natts)
    7373              :                 {
    7374          108 :                     value = values[anum];
    7375          108 :                     isnull = nulls[anum];
    7376          108 :                     valtype = TupleDescAttr(tupdesc, anum)->atttypid;
    7377          108 :                     valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
    7378          108 :                     anum++;
    7379              :                 }
    7380              :                 else
    7381              :                 {
    7382              :                     /* no source for destination column */
    7383            4 :                     value = (Datum) 0;
    7384            4 :                     isnull = true;
    7385            4 :                     valtype = UNKNOWNOID;
    7386            4 :                     valtypmod = -1;
    7387              : 
    7388              :                     /* When source value is missing */
    7389            4 :                     if (strict_multiassignment_level)
    7390            4 :                         ereport(strict_multiassignment_level,
    7391              :                                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    7392              :                                  errmsg("number of source and target fields in assignment does not match"),
    7393              :                         /* translator: %s represents a name of an extra check */
    7394              :                                  errdetail("%s check of %s is active.",
    7395              :                                            "strict_multi_assignment",
    7396              :                                            strict_multiassignment_level == ERROR ? "extra_errors" :
    7397              :                                            "extra_warnings"),
    7398              :                                  errhint("Make sure the query returns the exact list of columns.")));
    7399              :                 }
    7400              : 
    7401              :                 /* Cast the new value to the right type, if needed. */
    7402          108 :                 newvalues[fnum] = exec_cast_value(estate,
    7403              :                                                   value,
    7404              :                                                   &isnull,
    7405              :                                                   valtype,
    7406              :                                                   valtypmod,
    7407              :                                                   attr->atttypid,
    7408              :                                                   attr->atttypmod);
    7409          107 :                 newnulls[fnum] = isnull;
    7410              :             }
    7411              : 
    7412              :             /*
    7413              :              * When strict_multiassignment extra check is active, then ensure
    7414              :              * there are no unassigned source attributes.
    7415              :              */
    7416           51 :             if (strict_multiassignment_level && anum < td_natts)
    7417              :             {
    7418              :                 /* skip dropped columns in the source descriptor */
    7419            4 :                 while (anum < td_natts &&
    7420            4 :                        TupleDescAttr(tupdesc, anum)->attisdropped)
    7421            0 :                     anum++;
    7422              : 
    7423            4 :                 if (anum < td_natts)
    7424            4 :                     ereport(strict_multiassignment_level,
    7425              :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
    7426              :                              errmsg("number of source and target fields in assignment does not match"),
    7427              :                     /* translator: %s represents a name of an extra check */
    7428              :                              errdetail("%s check of %s is active.",
    7429              :                                        "strict_multi_assignment",
    7430              :                                        strict_multiassignment_level == ERROR ? "extra_errors" :
    7431              :                                        "extra_warnings"),
    7432              :                              errhint("Make sure the query returns the exact list of columns.")));
    7433              :             }
    7434              : 
    7435           47 :             values = newvalues;
    7436           47 :             nulls = newnulls;
    7437              :         }
    7438              : 
    7439              :         /* Insert the coerced field values into the new expanded record */
    7440           54 :         expanded_record_set_fields(newerh, values, nulls, !estate->atomic);
    7441              : 
    7442              :         /* Complete the assignment */
    7443           50 :         assign_record_var(estate, rec, newerh);
    7444              : 
    7445           50 :         return;
    7446              :     }
    7447              : 
    7448              :     /* newerh should not have been passed in non-RECORD cases */
    7449              :     Assert(newerh == NULL);
    7450              : 
    7451              :     /*
    7452              :      * For a row, we assign the individual field values to the variables the
    7453              :      * row points to.
    7454              :      *
    7455              :      * NOTE: both this code and the record code above silently ignore extra
    7456              :      * columns in the source and assume NULL for missing columns.  This is
    7457              :      * pretty dubious but it's the historical behavior.
    7458              :      *
    7459              :      * If we have no input data at all, we'll assign NULL to all columns of
    7460              :      * the row variable.
    7461              :      */
    7462        40757 :     if (target->dtype == PLPGSQL_DTYPE_ROW)
    7463              :     {
    7464        40757 :         PLpgSQL_row *row = (PLpgSQL_row *) target;
    7465              : 
    7466        40757 :         anum = 0;
    7467        85718 :         for (fnum = 0; fnum < row->nfields; fnum++)
    7468              :         {
    7469              :             PLpgSQL_var *var;
    7470              :             Datum       value;
    7471              :             bool        isnull;
    7472              :             Oid         valtype;
    7473              :             int32       valtypmod;
    7474              : 
    7475        44965 :             var = (PLpgSQL_var *) (estate->datums[row->varnos[fnum]]);
    7476              : 
    7477        44965 :             while (anum < td_natts &&
    7478        44828 :                    TupleDescAttr(tupdesc, anum)->attisdropped)
    7479            0 :                 anum++;         /* skip dropped column in tuple */
    7480              : 
    7481        44965 :             if (anum < td_natts)
    7482              :             {
    7483        44828 :                 value = values[anum];
    7484        44828 :                 isnull = nulls[anum];
    7485        44828 :                 valtype = TupleDescAttr(tupdesc, anum)->atttypid;
    7486        44828 :                 valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
    7487        44828 :                 anum++;
    7488              :             }
    7489              :             else
    7490              :             {
    7491              :                 /* no source for destination column */
    7492          137 :                 value = (Datum) 0;
    7493          137 :                 isnull = true;
    7494          137 :                 valtype = UNKNOWNOID;
    7495          137 :                 valtypmod = -1;
    7496              : 
    7497          137 :                 if (strict_multiassignment_level)
    7498            8 :                     ereport(strict_multiassignment_level,
    7499              :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
    7500              :                              errmsg("number of source and target fields in assignment does not match"),
    7501              :                     /* translator: %s represents a name of an extra check */
    7502              :                              errdetail("%s check of %s is active.",
    7503              :                                        "strict_multi_assignment",
    7504              :                                        strict_multiassignment_level == ERROR ? "extra_errors" :
    7505              :                                        "extra_warnings"),
    7506              :                              errhint("Make sure the query returns the exact list of columns.")));
    7507              :             }
    7508              : 
    7509        44961 :             exec_assign_value(estate, (PLpgSQL_datum *) var,
    7510              :                               value, isnull, valtype, valtypmod);
    7511              :         }
    7512              : 
    7513              :         /*
    7514              :          * When strict_multiassignment extra check is active, ensure there are
    7515              :          * no unassigned source attributes.
    7516              :          */
    7517        40753 :         if (strict_multiassignment_level && anum < td_natts)
    7518              :         {
    7519            8 :             while (anum < td_natts &&
    7520            8 :                    TupleDescAttr(tupdesc, anum)->attisdropped)
    7521            0 :                 anum++;         /* skip dropped column in tuple */
    7522              : 
    7523            8 :             if (anum < td_natts)
    7524            8 :                 ereport(strict_multiassignment_level,
    7525              :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    7526              :                          errmsg("number of source and target fields in assignment does not match"),
    7527              :                 /* translator: %s represents a name of an extra check */
    7528              :                          errdetail("%s check of %s is active.",
    7529              :                                    "strict_multi_assignment",
    7530              :                                    strict_multiassignment_level == ERROR ? "extra_errors" :
    7531              :                                    "extra_warnings"),
    7532              :                          errhint("Make sure the query returns the exact list of columns.")));
    7533              :         }
    7534              : 
    7535        40749 :         return;
    7536              :     }
    7537              : 
    7538            0 :     elog(ERROR, "unsupported target type: %d", target->dtype);
    7539              : }
    7540              : 
    7541              : /*
    7542              :  * compatible_tupdescs: detect whether two tupdescs are physically compatible
    7543              :  *
    7544              :  * TRUE indicates that a tuple satisfying src_tupdesc can be used directly as
    7545              :  * a value for a composite variable using dst_tupdesc.
    7546              :  */
    7547              : static bool
    7548          140 : compatible_tupdescs(TupleDesc src_tupdesc, TupleDesc dst_tupdesc)
    7549              : {
    7550              :     int         i;
    7551              : 
    7552              :     /* Possibly we could allow src_tupdesc to have extra columns? */
    7553          140 :     if (dst_tupdesc->natts != src_tupdesc->natts)
    7554           13 :         return false;
    7555              : 
    7556          339 :     for (i = 0; i < dst_tupdesc->natts; i++)
    7557              :     {
    7558          255 :         Form_pg_attribute dattr = TupleDescAttr(dst_tupdesc, i);
    7559          255 :         Form_pg_attribute sattr = TupleDescAttr(src_tupdesc, i);
    7560              : 
    7561          255 :         if (dattr->attisdropped != sattr->attisdropped)
    7562            4 :             return false;
    7563          251 :         if (!dattr->attisdropped)
    7564              :         {
    7565              :             /* Normal columns must match by type and typmod */
    7566          251 :             if (dattr->atttypid != sattr->atttypid ||
    7567          212 :                 (dattr->atttypmod >= 0 &&
    7568            8 :                  dattr->atttypmod != sattr->atttypmod))
    7569           39 :                 return false;
    7570              :         }
    7571              :         else
    7572              :         {
    7573              :             /* Dropped columns are OK as long as length/alignment match */
    7574            0 :             if (dattr->attlen != sattr->attlen ||
    7575            0 :                 dattr->attalign != sattr->attalign)
    7576            0 :                 return false;
    7577              :         }
    7578              :     }
    7579           84 :     return true;
    7580              : }
    7581              : 
    7582              : /* ----------
    7583              :  * make_tuple_from_row      Make a tuple from the values of a row object
    7584              :  *
    7585              :  * A NULL return indicates rowtype mismatch; caller must raise suitable error
    7586              :  *
    7587              :  * The result tuple is freshly palloc'd in caller's context.  Some junk
    7588              :  * may be left behind in eval_mcontext, too.
    7589              :  * ----------
    7590              :  */
    7591              : static HeapTuple
    7592         4192 : make_tuple_from_row(PLpgSQL_execstate *estate,
    7593              :                     PLpgSQL_row *row,
    7594              :                     TupleDesc tupdesc)
    7595              : {
    7596         4192 :     int         natts = tupdesc->natts;
    7597              :     HeapTuple   tuple;
    7598              :     Datum      *dvalues;
    7599              :     bool       *nulls;
    7600              :     int         i;
    7601              : 
    7602         4192 :     if (natts != row->nfields)
    7603            0 :         return NULL;
    7604              : 
    7605         4192 :     dvalues = (Datum *) eval_mcontext_alloc0(estate, natts * sizeof(Datum));
    7606         4192 :     nulls = (bool *) eval_mcontext_alloc(estate, natts * sizeof(bool));
    7607              : 
    7608        16578 :     for (i = 0; i < natts; i++)
    7609              :     {
    7610              :         Oid         fieldtypeid;
    7611              :         int32       fieldtypmod;
    7612              : 
    7613        12386 :         if (TupleDescAttr(tupdesc, i)->attisdropped)
    7614              :         {
    7615            0 :             nulls[i] = true;    /* leave the column as null */
    7616            0 :             continue;
    7617              :         }
    7618              : 
    7619        12386 :         exec_eval_datum(estate, estate->datums[row->varnos[i]],
    7620              :                         &fieldtypeid, &fieldtypmod,
    7621        12386 :                         &dvalues[i], &nulls[i]);
    7622        12386 :         if (fieldtypeid != TupleDescAttr(tupdesc, i)->atttypid)
    7623            0 :             return NULL;
    7624              :         /* XXX should we insist on typmod match, too? */
    7625              :     }
    7626              : 
    7627         4192 :     tuple = heap_form_tuple(tupdesc, dvalues, nulls);
    7628              : 
    7629         4192 :     return tuple;
    7630              : }
    7631              : 
    7632              : /*
    7633              :  * deconstruct_composite_datum      extract tuple+tupdesc from composite Datum
    7634              :  *
    7635              :  * The caller must supply a HeapTupleData variable, in which we set up a
    7636              :  * tuple header pointing to the composite datum's body.  To make the tuple
    7637              :  * value outlive that variable, caller would need to apply heap_copytuple...
    7638              :  * but current callers only need a short-lived tuple value anyway.
    7639              :  *
    7640              :  * Returns a pointer to the TupleDesc of the datum's rowtype.
    7641              :  * Caller is responsible for calling ReleaseTupleDesc when done with it.
    7642              :  *
    7643              :  * Note: it's caller's responsibility to be sure value is of composite type.
    7644              :  * Also, best to call this in a short-lived context, as it might leak memory.
    7645              :  */
    7646              : static TupleDesc
    7647         4438 : deconstruct_composite_datum(Datum value, HeapTupleData *tmptup)
    7648              : {
    7649              :     HeapTupleHeader td;
    7650              :     Oid         tupType;
    7651              :     int32       tupTypmod;
    7652              : 
    7653              :     /* Get tuple body (note this could involve detoasting) */
    7654         4438 :     td = DatumGetHeapTupleHeader(value);
    7655              : 
    7656              :     /* Build a temporary HeapTuple control structure */
    7657         4438 :     tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
    7658         4438 :     ItemPointerSetInvalid(&(tmptup->t_self));
    7659         4438 :     tmptup->t_tableOid = InvalidOid;
    7660         4438 :     tmptup->t_data = td;
    7661              : 
    7662              :     /* Extract rowtype info and find a tupdesc */
    7663         4438 :     tupType = HeapTupleHeaderGetTypeId(td);
    7664         4438 :     tupTypmod = HeapTupleHeaderGetTypMod(td);
    7665         4438 :     return lookup_rowtype_tupdesc(tupType, tupTypmod);
    7666              : }
    7667              : 
    7668              : /*
    7669              :  * exec_move_row_from_datum     Move a composite Datum into a record or row
    7670              :  *
    7671              :  * This is equivalent to deconstruct_composite_datum() followed by
    7672              :  * exec_move_row(), but we can optimize things if the Datum is an
    7673              :  * expanded-record reference.
    7674              :  *
    7675              :  * Note: it's caller's responsibility to be sure value is of composite type.
    7676              :  */
    7677              : static void
    7678          857 : exec_move_row_from_datum(PLpgSQL_execstate *estate,
    7679              :                          PLpgSQL_variable *target,
    7680              :                          Datum value)
    7681              : {
    7682              :     /* Check to see if source is an expanded record */
    7683          857 :     if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(value)))
    7684              :     {
    7685          166 :         ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(value);
    7686          166 :         ExpandedRecordHeader *newerh = NULL;
    7687              : 
    7688              :         Assert(erh->er_magic == ER_MAGIC);
    7689              : 
    7690              :         /* These cases apply if the target is record not row... */
    7691          166 :         if (target->dtype == PLPGSQL_DTYPE_REC)
    7692              :         {
    7693          166 :             PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
    7694              : 
    7695              :             /*
    7696              :              * If it's the same record already stored in the variable, do
    7697              :              * nothing.  This would happen only in silly cases like "r := r",
    7698              :              * but we need some check to avoid possibly freeing the variable's
    7699              :              * live value below.  Note that this applies even if what we have
    7700              :              * is a R/O pointer.
    7701              :              */
    7702          166 :             if (erh == rec->erh)
    7703            1 :                 return;
    7704              : 
    7705              :             /*
    7706              :              * Make sure rec->rectypeid is up-to-date before using it.
    7707              :              */
    7708          165 :             revalidate_rectypeid(rec);
    7709              : 
    7710              :             /*
    7711              :              * If we have a R/W pointer, we're allowed to just commandeer
    7712              :              * ownership of the expanded record.  If it's of the right type to
    7713              :              * put into the record variable, do that.  (Note we don't accept
    7714              :              * an expanded record of a composite-domain type as a RECORD
    7715              :              * value.  We'll treat it as the base composite type instead;
    7716              :              * compare logic in make_expanded_record_for_rec.)
    7717              :              */
    7718          165 :             if (VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(value)) &&
    7719            3 :                 (rec->rectypeid == erh->er_decltypeid ||
    7720            1 :                  (rec->rectypeid == RECORDOID &&
    7721            1 :                   !ExpandedRecordIsDomain(erh))))
    7722              :             {
    7723            3 :                 assign_record_var(estate, rec, erh);
    7724            3 :                 return;
    7725              :             }
    7726              : 
    7727              :             /*
    7728              :              * If we already have an expanded record object in the target
    7729              :              * variable, and the source record contains a valid tuple
    7730              :              * representation with the right rowtype, then we can skip making
    7731              :              * a new expanded record and just assign the tuple with
    7732              :              * expanded_record_set_tuple.  (We can't do the equivalent if we
    7733              :              * have to do field-by-field assignment, since that wouldn't be
    7734              :              * atomic if there's an error.)  We consider that there's a
    7735              :              * rowtype match only if it's the same named composite type or
    7736              :              * same registered rowtype; checking for matches of anonymous
    7737              :              * rowtypes would be more expensive than this is worth.
    7738              :              */
    7739          162 :             if (rec->erh &&
    7740            4 :                 (erh->flags & ER_FLAG_FVALUE_VALID) &&
    7741            2 :                 erh->er_typeid == rec->erh->er_typeid &&
    7742            1 :                 (erh->er_typeid != RECORDOID ||
    7743            0 :                  (erh->er_typmod == rec->erh->er_typmod &&
    7744            0 :                   erh->er_typmod >= 0)))
    7745              :             {
    7746            1 :                 expanded_record_set_tuple(rec->erh, erh->fvalue,
    7747            1 :                                           true, !estate->atomic);
    7748            1 :                 return;
    7749              :             }
    7750              : 
    7751              :             /*
    7752              :              * Otherwise we're gonna need a new expanded record object.  Make
    7753              :              * it here in hopes of piggybacking on the source object's
    7754              :              * previous typcache lookup.
    7755              :              */
    7756          161 :             newerh = make_expanded_record_for_rec(estate, rec, NULL, erh);
    7757              : 
    7758              :             /*
    7759              :              * If the expanded record contains a valid tuple representation,
    7760              :              * and we don't need rowtype conversion, then just copying the
    7761              :              * tuple is probably faster than field-by-field processing.  (This
    7762              :              * isn't duplicative of the previous check, since here we will
    7763              :              * catch the case where the record variable was previously empty.)
    7764              :              */
    7765          161 :             if ((erh->flags & ER_FLAG_FVALUE_VALID) &&
    7766          152 :                 (rec->rectypeid == RECORDOID ||
    7767            4 :                  rec->rectypeid == erh->er_typeid))
    7768              :             {
    7769          151 :                 expanded_record_set_tuple(newerh, erh->fvalue,
    7770          151 :                                           true, !estate->atomic);
    7771          151 :                 assign_record_var(estate, rec, newerh);
    7772          151 :                 return;
    7773              :             }
    7774              : 
    7775              :             /*
    7776              :              * Need to special-case empty source record, else code below would
    7777              :              * leak newerh.
    7778              :              */
    7779           10 :             if (ExpandedRecordIsEmpty(erh))
    7780              :             {
    7781              :                 /* Set newerh to a row of NULLs */
    7782            0 :                 deconstruct_expanded_record(newerh);
    7783            0 :                 assign_record_var(estate, rec, newerh);
    7784            0 :                 return;
    7785              :             }
    7786              :         }                       /* end of record-target-only cases */
    7787              : 
    7788              :         /*
    7789              :          * If the source expanded record is empty, we should treat that like a
    7790              :          * NULL tuple value.  (We're unlikely to see such a case, but we must
    7791              :          * check this; deconstruct_expanded_record would cause a change of
    7792              :          * logical state, which is not OK.)
    7793              :          */
    7794           10 :         if (ExpandedRecordIsEmpty(erh))
    7795              :         {
    7796            0 :             exec_move_row(estate, target, NULL,
    7797              :                           expanded_record_get_tupdesc(erh));
    7798            0 :             return;
    7799              :         }
    7800              : 
    7801              :         /*
    7802              :          * Otherwise, ensure that the source record is deconstructed, and
    7803              :          * assign from its field values.
    7804              :          */
    7805           10 :         deconstruct_expanded_record(erh);
    7806           10 :         exec_move_row_from_fields(estate, target, newerh,
    7807              :                                   erh->dvalues, erh->dnulls,
    7808              :                                   expanded_record_get_tupdesc(erh));
    7809              :     }
    7810              :     else
    7811              :     {
    7812              :         /*
    7813              :          * Nope, we've got a plain composite Datum.  Deconstruct it; but we
    7814              :          * don't use deconstruct_composite_datum(), because we may be able to
    7815              :          * skip calling lookup_rowtype_tupdesc().
    7816              :          */
    7817              :         HeapTupleHeader td;
    7818              :         HeapTupleData tmptup;
    7819              :         Oid         tupType;
    7820              :         int32       tupTypmod;
    7821              :         TupleDesc   tupdesc;
    7822              :         MemoryContext oldcontext;
    7823              : 
    7824              :         /* Ensure that any detoasted data winds up in the eval_mcontext */
    7825          691 :         oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    7826              :         /* Get tuple body (note this could involve detoasting) */
    7827          691 :         td = DatumGetHeapTupleHeader(value);
    7828          691 :         MemoryContextSwitchTo(oldcontext);
    7829              : 
    7830              :         /* Build a temporary HeapTuple control structure */
    7831          691 :         tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
    7832          691 :         ItemPointerSetInvalid(&(tmptup.t_self));
    7833          691 :         tmptup.t_tableOid = InvalidOid;
    7834          691 :         tmptup.t_data = td;
    7835              : 
    7836              :         /* Extract rowtype info */
    7837          691 :         tupType = HeapTupleHeaderGetTypeId(td);
    7838          691 :         tupTypmod = HeapTupleHeaderGetTypMod(td);
    7839              : 
    7840              :         /* Now, if the target is record not row, maybe we can optimize ... */
    7841          691 :         if (target->dtype == PLPGSQL_DTYPE_REC)
    7842              :         {
    7843          663 :             PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
    7844              : 
    7845              :             /*
    7846              :              * If we already have an expanded record object in the target
    7847              :              * variable, and the source datum has a matching rowtype, then we
    7848              :              * can skip making a new expanded record and just assign the tuple
    7849              :              * with expanded_record_set_tuple.  We consider that there's a
    7850              :              * rowtype match only if it's the same named composite type or
    7851              :              * same registered rowtype.  (Checking to reject an anonymous
    7852              :              * rowtype here should be redundant, but let's be safe.)
    7853              :              */
    7854          663 :             if (rec->erh &&
    7855          102 :                 tupType == rec->erh->er_typeid &&
    7856            2 :                 (tupType != RECORDOID ||
    7857            2 :                  (tupTypmod == rec->erh->er_typmod &&
    7858              :                   tupTypmod >= 0)))
    7859              :             {
    7860           88 :                 expanded_record_set_tuple(rec->erh, &tmptup,
    7861           88 :                                           true, !estate->atomic);
    7862          613 :                 return;
    7863              :             }
    7864              : 
    7865              :             /*
    7866              :              * If the source datum has a rowtype compatible with the target
    7867              :              * variable, just build a new expanded record and assign the tuple
    7868              :              * into it.  Using make_expanded_record_from_typeid() here saves
    7869              :              * one typcache lookup compared to the code below.
    7870              :              */
    7871          575 :             if (rec->rectypeid == RECORDOID || rec->rectypeid == tupType)
    7872              :             {
    7873              :                 ExpandedRecordHeader *newerh;
    7874          525 :                 MemoryContext mcontext = get_eval_mcontext(estate);
    7875              : 
    7876          525 :                 newerh = make_expanded_record_from_typeid(tupType, tupTypmod,
    7877              :                                                           mcontext);
    7878          525 :                 expanded_record_set_tuple(newerh, &tmptup,
    7879          525 :                                           true, !estate->atomic);
    7880          525 :                 assign_record_var(estate, rec, newerh);
    7881          525 :                 return;
    7882              :             }
    7883              : 
    7884              :             /*
    7885              :              * Otherwise, we're going to need conversion, so fall through to
    7886              :              * do it the hard way.
    7887              :              */
    7888              :         }
    7889              : 
    7890              :         /*
    7891              :          * ROW target, or unoptimizable RECORD target, so we have to expend a
    7892              :          * lookup to obtain the source datum's tupdesc.
    7893              :          */
    7894           78 :         tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
    7895              : 
    7896              :         /* Do the move */
    7897           78 :         exec_move_row(estate, target, &tmptup, tupdesc);
    7898              : 
    7899              :         /* Release tupdesc usage count */
    7900           71 :         ReleaseTupleDesc(tupdesc);
    7901              :     }
    7902              : }
    7903              : 
    7904              : /*
    7905              :  * If we have not created an expanded record to hold the record variable's
    7906              :  * value, do so.  The expanded record will be "empty", so this does not
    7907              :  * change the logical state of the record variable: it's still NULL.
    7908              :  * However, now we'll have a tupdesc with which we can e.g. look up fields.
    7909              :  */
    7910              : static void
    7911           64 : instantiate_empty_record_variable(PLpgSQL_execstate *estate, PLpgSQL_rec *rec)
    7912              : {
    7913              :     Assert(rec->erh == NULL);    /* else caller error */
    7914              : 
    7915              :     /* If declared type is RECORD, we can't instantiate */
    7916           64 :     if (rec->rectypeid == RECORDOID)
    7917            2 :         ereport(ERROR,
    7918              :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    7919              :                  errmsg("record \"%s\" is not assigned yet", rec->refname),
    7920              :                  errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
    7921              : 
    7922              :     /* Make sure rec->rectypeid is up-to-date before using it */
    7923           62 :     revalidate_rectypeid(rec);
    7924              : 
    7925              :     /* OK, do it */
    7926           61 :     rec->erh = make_expanded_record_from_typeid(rec->rectypeid, -1,
    7927              :                                                 estate->datum_context);
    7928           61 : }
    7929              : 
    7930              : /* ----------
    7931              :  * convert_value_to_string          Convert a non-null Datum to C string
    7932              :  *
    7933              :  * Note: the result is in the estate's eval_mcontext, and will be cleared
    7934              :  * by the next exec_eval_cleanup() call.  The invoked output function might
    7935              :  * leave additional cruft there as well, so just pfree'ing the result string
    7936              :  * would not be enough to avoid memory leaks if we did not do it like this.
    7937              :  * In most usages the Datum being passed in is also in that context (if
    7938              :  * pass-by-reference) and so an exec_eval_cleanup() call is needed anyway.
    7939              :  *
    7940              :  * Note: not caching the conversion function lookup is bad for performance.
    7941              :  * However, this function isn't currently used in any places where an extra
    7942              :  * catalog lookup or two seems like a big deal.
    7943              :  * ----------
    7944              :  */
    7945              : static char *
    7946        49298 : convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
    7947              : {
    7948              :     char       *result;
    7949              :     MemoryContext oldcontext;
    7950              :     Oid         typoutput;
    7951              :     bool        typIsVarlena;
    7952              : 
    7953        49298 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    7954        49298 :     getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
    7955        49298 :     result = OidOutputFunctionCall(typoutput, value);
    7956        49298 :     MemoryContextSwitchTo(oldcontext);
    7957              : 
    7958        49298 :     return result;
    7959              : }
    7960              : 
    7961              : /* ----------
    7962              :  * exec_cast_value          Cast a value if required
    7963              :  *
    7964              :  * Note that *isnull is an input and also an output parameter.  While it's
    7965              :  * unlikely that a cast operation would produce null from non-null or vice
    7966              :  * versa, that could happen in principle.
    7967              :  *
    7968              :  * Note: the estate's eval_mcontext is used for temporary storage, and may
    7969              :  * also contain the result Datum if we have to do a conversion to a pass-
    7970              :  * by-reference data type.  Be sure to do an exec_eval_cleanup() call when
    7971              :  * done with the result.
    7972              :  * ----------
    7973              :  */
    7974              : static inline Datum
    7975       243730 : exec_cast_value(PLpgSQL_execstate *estate,
    7976              :                 Datum value, bool *isnull,
    7977              :                 Oid valtype, int32 valtypmod,
    7978              :                 Oid reqtype, int32 reqtypmod)
    7979              : {
    7980              :     /*
    7981              :      * If the type of the given value isn't what's requested, convert it.
    7982              :      */
    7983       243730 :     if (valtype != reqtype ||
    7984            0 :         (valtypmod != reqtypmod && reqtypmod != -1))
    7985              :     {
    7986              :         /* We keep the slow path out-of-line. */
    7987         2669 :         value = do_cast_value(estate, value, isnull, valtype, valtypmod,
    7988              :                               reqtype, reqtypmod);
    7989              :     }
    7990              : 
    7991       243690 :     return value;
    7992              : }
    7993              : 
    7994              : /* ----------
    7995              :  * do_cast_value            Slow path for exec_cast_value.
    7996              :  * ----------
    7997              :  */
    7998              : static Datum
    7999         2669 : do_cast_value(PLpgSQL_execstate *estate,
    8000              :               Datum value, bool *isnull,
    8001              :               Oid valtype, int32 valtypmod,
    8002              :               Oid reqtype, int32 reqtypmod)
    8003              : {
    8004              :     plpgsql_CastHashEntry *cast_entry;
    8005              : 
    8006         2669 :     cast_entry = get_cast_hashentry(estate,
    8007              :                                     valtype, valtypmod,
    8008              :                                     reqtype, reqtypmod);
    8009         2669 :     if (cast_entry)
    8010              :     {
    8011         2669 :         ExprContext *econtext = estate->eval_econtext;
    8012              :         MemoryContext oldcontext;
    8013              : 
    8014         2669 :         oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    8015              : 
    8016         2669 :         econtext->caseValue_datum = value;
    8017         2669 :         econtext->caseValue_isNull = *isnull;
    8018              : 
    8019         2669 :         cast_entry->cast_in_use = true;
    8020              : 
    8021         2669 :         value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
    8022              :                              isnull);
    8023              : 
    8024         2629 :         cast_entry->cast_in_use = false;
    8025              : 
    8026         2629 :         MemoryContextSwitchTo(oldcontext);
    8027              :     }
    8028              : 
    8029         2629 :     return value;
    8030              : }
    8031              : 
    8032              : /* ----------
    8033              :  * get_cast_hashentry           Look up how to perform a type cast
    8034              :  *
    8035              :  * Returns a plpgsql_CastHashEntry if an expression has to be evaluated,
    8036              :  * or NULL if the cast is a mere no-op relabeling.  If there's work to be
    8037              :  * done, the cast_exprstate field contains an expression evaluation tree
    8038              :  * based on a CaseTestExpr input, and the cast_in_use field should be set
    8039              :  * true while executing it.
    8040              :  * ----------
    8041              :  */
    8042              : static plpgsql_CastHashEntry *
    8043         2669 : get_cast_hashentry(PLpgSQL_execstate *estate,
    8044              :                    Oid srctype, int32 srctypmod,
    8045              :                    Oid dsttype, int32 dsttypmod)
    8046              : {
    8047              :     plpgsql_CastHashKey cast_key;
    8048              :     plpgsql_CastHashEntry *cast_entry;
    8049              :     plpgsql_CastExprHashEntry *expr_entry;
    8050              :     bool        found;
    8051              :     LocalTransactionId curlxid;
    8052              :     MemoryContext oldcontext;
    8053              : 
    8054              :     /* Look for existing entry */
    8055         2669 :     cast_key.srctype = srctype;
    8056         2669 :     cast_key.dsttype = dsttype;
    8057         2669 :     cast_key.srctypmod = srctypmod;
    8058         2669 :     cast_key.dsttypmod = dsttypmod;
    8059         2669 :     cast_entry = (plpgsql_CastHashEntry *) hash_search(estate->cast_hash,
    8060              :                                                        &cast_key,
    8061              :                                                        HASH_ENTER, &found);
    8062         2669 :     if (!found)                 /* initialize if new entry */
    8063              :     {
    8064              :         /* We need a second lookup to see if a cast_expr_hash entry exists */
    8065          252 :         expr_entry = (plpgsql_CastExprHashEntry *) hash_search(cast_expr_hash,
    8066              :                                                                &cast_key,
    8067              :                                                                HASH_ENTER,
    8068              :                                                                &found);
    8069          252 :         if (!found)             /* initialize if new expr entry */
    8070          215 :             expr_entry->cast_cexpr = NULL;
    8071              : 
    8072          252 :         cast_entry->cast_centry = expr_entry;
    8073          252 :         cast_entry->cast_exprstate = NULL;
    8074          252 :         cast_entry->cast_in_use = false;
    8075          252 :         cast_entry->cast_lxid = InvalidLocalTransactionId;
    8076              :     }
    8077              :     else
    8078              :     {
    8079              :         /* Use always-valid link to avoid a second hash lookup */
    8080         2417 :         expr_entry = cast_entry->cast_centry;
    8081              :     }
    8082              : 
    8083         2669 :     if (expr_entry->cast_cexpr == NULL ||
    8084         2454 :         !expr_entry->cast_cexpr->is_valid)
    8085              :     {
    8086              :         /*
    8087              :          * We've not looked up this coercion before, or we have but the cached
    8088              :          * expression has been invalidated.
    8089              :          */
    8090              :         Node       *cast_expr;
    8091              :         CachedExpression *cast_cexpr;
    8092              :         CaseTestExpr *placeholder;
    8093              : 
    8094              :         /*
    8095              :          * Drop old cached expression if there is one.
    8096              :          */
    8097          254 :         if (expr_entry->cast_cexpr)
    8098              :         {
    8099           39 :             FreeCachedExpression(expr_entry->cast_cexpr);
    8100           39 :             expr_entry->cast_cexpr = NULL;
    8101              :         }
    8102              : 
    8103              :         /*
    8104              :          * Since we could easily fail (no such coercion), construct a
    8105              :          * temporary coercion expression tree in the short-lived
    8106              :          * eval_mcontext, then if successful save it as a CachedExpression.
    8107              :          */
    8108          254 :         oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    8109              : 
    8110              :         /*
    8111              :          * We use a CaseTestExpr as the base of the coercion tree, since it's
    8112              :          * very cheap to insert the source value for that.
    8113              :          */
    8114          254 :         placeholder = makeNode(CaseTestExpr);
    8115          254 :         placeholder->typeId = srctype;
    8116          254 :         placeholder->typeMod = srctypmod;
    8117          254 :         placeholder->collation = get_typcollation(srctype);
    8118              : 
    8119              :         /*
    8120              :          * Apply coercion.  We use the special coercion context
    8121              :          * COERCION_PLPGSQL to match plpgsql's historical behavior, namely
    8122              :          * that any cast not available at ASSIGNMENT level will be implemented
    8123              :          * as an I/O coercion.  (It's somewhat dubious that we prefer I/O
    8124              :          * coercion over cast pathways that exist at EXPLICIT level.  Changing
    8125              :          * that would cause assorted minor behavioral differences though, and
    8126              :          * a user who wants the explicit-cast behavior can always write an
    8127              :          * explicit cast.)
    8128              :          *
    8129              :          * If source type is UNKNOWN, coerce_to_target_type will fail (it only
    8130              :          * expects to see that for Const input nodes), so don't call it; we'll
    8131              :          * apply CoerceViaIO instead.  Likewise, it doesn't currently work for
    8132              :          * coercing RECORD to some other type, so skip for that too.
    8133              :          */
    8134          254 :         if (srctype == UNKNOWNOID || srctype == RECORDOID)
    8135           73 :             cast_expr = NULL;
    8136              :         else
    8137          181 :             cast_expr = coerce_to_target_type(NULL,
    8138              :                                               (Node *) placeholder, srctype,
    8139              :                                               dsttype, dsttypmod,
    8140              :                                               COERCION_PLPGSQL,
    8141              :                                               COERCE_IMPLICIT_CAST,
    8142              :                                               -1);
    8143              : 
    8144              :         /*
    8145              :          * If there's no cast path according to the parser, fall back to using
    8146              :          * an I/O coercion; this is semantically dubious but matches plpgsql's
    8147              :          * historical behavior.  We would need something of the sort for
    8148              :          * UNKNOWN literals in any case.  (This is probably now only reachable
    8149              :          * in the case where srctype is UNKNOWN/RECORD.)
    8150              :          */
    8151          254 :         if (cast_expr == NULL)
    8152              :         {
    8153           73 :             CoerceViaIO *iocoerce = makeNode(CoerceViaIO);
    8154              : 
    8155           73 :             iocoerce->arg = (Expr *) placeholder;
    8156           73 :             iocoerce->resulttype = dsttype;
    8157           73 :             iocoerce->resultcollid = InvalidOid;
    8158           73 :             iocoerce->coerceformat = COERCE_IMPLICIT_CAST;
    8159           73 :             iocoerce->location = -1;
    8160           73 :             cast_expr = (Node *) iocoerce;
    8161           73 :             if (dsttypmod != -1)
    8162            0 :                 cast_expr = coerce_to_target_type(NULL,
    8163              :                                                   cast_expr, dsttype,
    8164              :                                                   dsttype, dsttypmod,
    8165              :                                                   COERCION_ASSIGNMENT,
    8166              :                                                   COERCE_IMPLICIT_CAST,
    8167              :                                                   -1);
    8168              :         }
    8169              : 
    8170              :         /* Note: we don't bother labeling the expression tree with collation */
    8171              : 
    8172              :         /* Plan the expression and build a CachedExpression */
    8173          254 :         cast_cexpr = GetCachedExpression(cast_expr);
    8174          254 :         cast_expr = cast_cexpr->expr;
    8175              : 
    8176              :         /* Detect whether we have a no-op (RelabelType) coercion */
    8177          254 :         if (IsA(cast_expr, RelabelType) &&
    8178           14 :             ((RelabelType *) cast_expr)->arg == (Expr *) placeholder)
    8179            0 :             cast_expr = NULL;
    8180              : 
    8181              :         /* Now we can fill in the expression hashtable entry. */
    8182          254 :         expr_entry->cast_cexpr = cast_cexpr;
    8183          254 :         expr_entry->cast_expr = (Expr *) cast_expr;
    8184              : 
    8185              :         /* Be sure to reset the exprstate hashtable entry, too. */
    8186          254 :         cast_entry->cast_exprstate = NULL;
    8187          254 :         cast_entry->cast_in_use = false;
    8188          254 :         cast_entry->cast_lxid = InvalidLocalTransactionId;
    8189              : 
    8190          254 :         MemoryContextSwitchTo(oldcontext);
    8191              :     }
    8192              : 
    8193              :     /* Done if we have determined that this is a no-op cast. */
    8194         2669 :     if (expr_entry->cast_expr == NULL)
    8195            0 :         return NULL;
    8196              : 
    8197              :     /*
    8198              :      * Prepare the expression for execution, if it's not been done already in
    8199              :      * the current transaction; also, if it's marked busy in the current
    8200              :      * transaction, abandon that expression tree and build a new one, so as to
    8201              :      * avoid potential problems with recursive cast expressions and failed
    8202              :      * executions.  (We will leak some memory intra-transaction if that
    8203              :      * happens a lot, but we don't expect it to.)  It's okay to update the
    8204              :      * hash table with the new tree because all plpgsql functions within a
    8205              :      * given transaction share the same simple_eval_estate.  (Well, regular
    8206              :      * functions do; DO blocks have private simple_eval_estates, and private
    8207              :      * cast hash tables to go with them.)
    8208              :      */
    8209         2669 :     curlxid = MyProc->vxid.lxid;
    8210         2669 :     if (cast_entry->cast_lxid != curlxid || cast_entry->cast_in_use)
    8211              :     {
    8212          501 :         oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
    8213          501 :         cast_entry->cast_exprstate = ExecInitExpr(expr_entry->cast_expr, NULL);
    8214          501 :         cast_entry->cast_in_use = false;
    8215          501 :         cast_entry->cast_lxid = curlxid;
    8216          501 :         MemoryContextSwitchTo(oldcontext);
    8217              :     }
    8218              : 
    8219         2669 :     return cast_entry;
    8220              : }
    8221              : 
    8222              : 
    8223              : /* ----------
    8224              :  * exec_simple_check_plan -     Check if a plan is simple enough to
    8225              :  *                              be evaluated by ExecEvalExpr() instead
    8226              :  *                              of SPI.
    8227              :  *
    8228              :  * Note: the refcount manipulations in this function assume that expr->plan
    8229              :  * is a "saved" SPI plan.  That's a bit annoying from the caller's standpoint,
    8230              :  * but it's otherwise difficult to avoid leaking the plan on failure.
    8231              :  * ----------
    8232              :  */
    8233              : static void
    8234        17827 : exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
    8235              : {
    8236              :     List       *plansources;
    8237              :     CachedPlanSource *plansource;
    8238              :     CachedPlan *cplan;
    8239              :     MemoryContext oldcontext;
    8240              : 
    8241              :     /*
    8242              :      * Initialize to "not simple", and reset R/W optimizability.
    8243              :      */
    8244        17827 :     expr->expr_simple_expr = NULL;
    8245        17827 :     expr->expr_rwopt = PLPGSQL_RWOPT_UNKNOWN;
    8246        17827 :     expr->expr_rw_param = NULL;
    8247              : 
    8248              :     /*
    8249              :      * Check the analyzed-and-rewritten form of the query to see if we will be
    8250              :      * able to treat it as a simple expression.  Since this function is only
    8251              :      * called immediately after creating the CachedPlanSource, we need not
    8252              :      * worry about the query being stale.
    8253              :      */
    8254        17827 :     if (!exec_is_simple_query(expr))
    8255         2423 :         return;
    8256              : 
    8257              :     /* exec_is_simple_query verified that there's just one CachedPlanSource */
    8258        15404 :     plansources = SPI_plan_get_plan_sources(expr->plan);
    8259        15404 :     plansource = (CachedPlanSource *) linitial(plansources);
    8260              : 
    8261              :     /*
    8262              :      * Get the generic plan for the query.  If replanning is needed, do that
    8263              :      * work in the eval_mcontext.  (Note that replanning could throw an error,
    8264              :      * in which case the expr is left marked "not simple", which is fine.)
    8265              :      */
    8266        15404 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    8267        15404 :     cplan = SPI_plan_get_cached_plan(expr->plan);
    8268        15379 :     MemoryContextSwitchTo(oldcontext);
    8269              : 
    8270              :     /* Can't fail, because we checked for a single CachedPlanSource above */
    8271              :     Assert(cplan != NULL);
    8272              : 
    8273              :     /*
    8274              :      * Verify that plancache.c thinks the plan is simple enough to use
    8275              :      * CachedPlanIsSimplyValid.  Given the restrictions above, it's unlikely
    8276              :      * that this could fail, but if it does, just treat plan as not simple. On
    8277              :      * success, save a refcount on the plan in the simple-expression resowner.
    8278              :      */
    8279        15379 :     if (CachedPlanAllowsSimpleValidityCheck(plansource, cplan,
    8280              :                                             estate->simple_eval_resowner))
    8281              :     {
    8282              :         /* Remember that we have the refcount */
    8283        15379 :         expr->expr_simple_plansource = plansource;
    8284        15379 :         expr->expr_simple_plan = cplan;
    8285        15379 :         expr->expr_simple_plan_lxid = MyProc->vxid.lxid;
    8286              : 
    8287              :         /* Share the remaining work with the replan code path */
    8288        15379 :         exec_save_simple_expr(expr, cplan);
    8289              :     }
    8290              : 
    8291              :     /*
    8292              :      * Release the plan refcount obtained by SPI_plan_get_cached_plan.  (This
    8293              :      * refcount is held by the wrong resowner, so we can't just repurpose it.)
    8294              :      */
    8295        15379 :     ReleaseCachedPlan(cplan, CurrentResourceOwner);
    8296              : }
    8297              : 
    8298              : /*
    8299              :  * exec_is_simple_query - precheck a query tree to see if it might be simple
    8300              :  *
    8301              :  * Check the analyzed-and-rewritten form of a query to see if we will be
    8302              :  * able to treat it as a simple expression.  It is caller's responsibility
    8303              :  * that the CachedPlanSource be up-to-date.
    8304              :  */
    8305              : static bool
    8306        21420 : exec_is_simple_query(PLpgSQL_expr *expr)
    8307              : {
    8308              :     List       *plansources;
    8309              :     CachedPlanSource *plansource;
    8310              :     Query      *query;
    8311              : 
    8312              :     /*
    8313              :      * We can only test queries that resulted in exactly one CachedPlanSource.
    8314              :      */
    8315        21420 :     plansources = SPI_plan_get_plan_sources(expr->plan);
    8316        21420 :     if (list_length(plansources) != 1)
    8317            0 :         return false;
    8318        21420 :     plansource = (CachedPlanSource *) linitial(plansources);
    8319              : 
    8320              :     /*
    8321              :      * 1. There must be one single querytree.
    8322              :      */
    8323        21420 :     if (list_length(plansource->query_list) != 1)
    8324            0 :         return false;
    8325        21420 :     query = (Query *) linitial(plansource->query_list);
    8326              : 
    8327              :     /*
    8328              :      * 2. It must be a plain SELECT query without any input tables.
    8329              :      */
    8330        21420 :     if (!IsA(query, Query))
    8331            0 :         return false;
    8332        21420 :     if (query->commandType != CMD_SELECT)
    8333         1240 :         return false;
    8334        20180 :     if (query->rtable != NIL)
    8335          724 :         return false;
    8336              : 
    8337              :     /*
    8338              :      * 3. Can't have any subplans, aggregates, qual clauses either.  (These
    8339              :      * tests should generally match what inline_function() checks before
    8340              :      * inlining a SQL function; otherwise, inlining could change our
    8341              :      * conclusion about whether an expression is simple, which we don't want.)
    8342              :      */
    8343        19456 :     if (query->hasAggs ||
    8344        19456 :         query->hasWindowFuncs ||
    8345        19456 :         query->hasTargetSRFs ||
    8346        19430 :         query->hasSubLinks ||
    8347        19073 :         query->cteList ||
    8348        19073 :         query->jointree->fromlist ||
    8349        19073 :         query->jointree->quals ||
    8350        19073 :         query->groupClause ||
    8351        19073 :         query->groupingSets ||
    8352        19073 :         query->havingQual ||
    8353        19073 :         query->windowClause ||
    8354        19073 :         query->distinctClause ||
    8355        19073 :         query->sortClause ||
    8356        19073 :         query->limitOffset ||
    8357        19073 :         query->limitCount ||
    8358        19073 :         query->setOperations)
    8359          383 :         return false;
    8360              : 
    8361              :     /*
    8362              :      * 4. The query must have a single attribute as result.
    8363              :      */
    8364        19073 :     if (list_length(query->targetList) != 1)
    8365           77 :         return false;
    8366              : 
    8367              :     /*
    8368              :      * OK, we can treat it as a simple plan.
    8369              :      */
    8370        18996 :     return true;
    8371              : }
    8372              : 
    8373              : /*
    8374              :  * exec_save_simple_expr --- extract simple expression from CachedPlan
    8375              :  */
    8376              : static void
    8377        18971 : exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
    8378              : {
    8379              :     PlannedStmt *stmt;
    8380              :     Plan       *plan;
    8381              :     Expr       *tle_expr;
    8382              : 
    8383              :     /*
    8384              :      * Given the checks that exec_simple_check_plan did, none of the Asserts
    8385              :      * here should ever fail.
    8386              :      */
    8387              : 
    8388              :     /* Extract the single PlannedStmt */
    8389              :     Assert(list_length(cplan->stmt_list) == 1);
    8390        18971 :     stmt = linitial_node(PlannedStmt, cplan->stmt_list);
    8391              :     Assert(stmt->commandType == CMD_SELECT);
    8392              : 
    8393              :     /*
    8394              :      * Ordinarily, the plan node should be a simple Result.  However, if
    8395              :      * debug_parallel_query is on, the planner might've stuck a Gather node
    8396              :      * atop that; and/or if this plan is for a scrollable cursor, the planner
    8397              :      * might've stuck a Material node atop it.  The simplest way to deal with
    8398              :      * this is to look through the Gather and/or Material nodes.  The upper
    8399              :      * node's tlist would normally contain a Var referencing the child node's
    8400              :      * output ... but setrefs.c might also have copied a Const as-is.
    8401              :      */
    8402        18971 :     plan = stmt->planTree;
    8403              :     for (;;)
    8404              :     {
    8405              :         /* Extract the single tlist expression */
    8406            0 :         Assert(list_length(plan->targetlist) == 1);
    8407        18971 :         tle_expr = linitial_node(TargetEntry, plan->targetlist)->expr;
    8408              : 
    8409        18971 :         if (IsA(plan, Result))
    8410              :         {
    8411              :             Assert(plan->lefttree == NULL &&
    8412              :                    plan->righttree == NULL &&
    8413              :                    plan->initPlan == NULL &&
    8414              :                    plan->qual == NULL &&
    8415              :                    ((Result *) plan)->resconstantqual == NULL);
    8416        18970 :             break;
    8417              :         }
    8418            1 :         else if (IsA(plan, Gather) || IsA(plan, Material))
    8419              :         {
    8420              :             Assert(plan->lefttree != NULL &&
    8421              :                    plan->righttree == NULL &&
    8422              :                    plan->initPlan == NULL &&
    8423              :                    plan->qual == NULL);
    8424              :             /* If setrefs.c copied up a Const, no need to look further */
    8425            1 :             if (IsA(tle_expr, Const))
    8426            1 :                 break;
    8427              :             /* Otherwise, it better be an outer Var */
    8428              :             Assert(IsA(tle_expr, Var));
    8429              :             Assert(((Var *) tle_expr)->varno == OUTER_VAR);
    8430              :             /* Descend to the child node */
    8431            0 :             plan = plan->lefttree;
    8432              :         }
    8433              :         else
    8434            0 :             elog(ERROR, "unexpected plan node type: %d",
    8435              :                  (int) nodeTag(plan));
    8436              :     }
    8437              : 
    8438              :     /*
    8439              :      * Save the simple expression, and initialize state to "not valid in
    8440              :      * current transaction".
    8441              :      */
    8442        18971 :     expr->expr_simple_expr = tle_expr;
    8443        18971 :     expr->expr_simple_state = NULL;
    8444        18971 :     expr->expr_simple_in_use = false;
    8445        18971 :     expr->expr_simple_lxid = InvalidLocalTransactionId;
    8446              :     /* Also stash away the expression result type */
    8447        18971 :     expr->expr_simple_type = exprType((Node *) tle_expr);
    8448        18971 :     expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
    8449              :     /* We also want to remember if it is immutable or not */
    8450        18971 :     expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr);
    8451        18971 : }
    8452              : 
    8453              : /*
    8454              :  * exec_check_rw_parameter --- can we pass expanded object as read/write param?
    8455              :  *
    8456              :  * There are two separate cases in which we can optimize an update to a
    8457              :  * variable that has a read/write expanded value by letting the called
    8458              :  * expression operate directly on the expanded value.  In both cases we
    8459              :  * are considering assignments like "var := array_append(var, foo)" where
    8460              :  * the assignment target is also an input to the RHS expression.
    8461              :  *
    8462              :  * Case 1 (RWOPT_TRANSFER rule): if the variable is "local" in the sense that
    8463              :  * its declaration is not outside any BEGIN...EXCEPTION block surrounding the
    8464              :  * assignment, then we do not need to worry about preserving its value if the
    8465              :  * RHS expression throws an error.  If in addition the variable is referenced
    8466              :  * exactly once in the RHS expression, then we can optimize by converting the
    8467              :  * read/write expanded value into a transient value within the expression
    8468              :  * evaluation context, and then setting the variable's recorded value to NULL
    8469              :  * to prevent double-free attempts.  This works regardless of any other
    8470              :  * details of the RHS expression.  If the expression eventually returns that
    8471              :  * same expanded object (possibly modified) then the variable will re-acquire
    8472              :  * ownership; while if it returns something else or throws an error, the
    8473              :  * expanded object will be discarded as part of cleanup of the evaluation
    8474              :  * context.
    8475              :  *
    8476              :  * Case 2 (RWOPT_INPLACE rule): if we have a non-local assignment or if
    8477              :  * it looks like "var := array_append(var, var[1])" with multiple references
    8478              :  * to the target variable, then we can't use case 1.  Nonetheless, if the
    8479              :  * top-level function is trusted not to corrupt its argument in case of an
    8480              :  * error, then when the var has an expanded object as value, it is safe to
    8481              :  * pass the value as a read/write pointer to the top-level function and let
    8482              :  * the function modify the value in-place.  (Any other references have to be
    8483              :  * passed as read-only pointers as usual.)  Only the top-level function has to
    8484              :  * be trusted, since if anything further down fails, the object hasn't been
    8485              :  * modified yet.
    8486              :  *
    8487              :  * This function checks to see if the assignment is optimizable according
    8488              :  * to either rule, and updates expr->expr_rwopt accordingly.  In addition,
    8489              :  * it sets expr->expr_rw_param to the address of the Param within the
    8490              :  * expression that can be passed as read/write (there can be only one);
    8491              :  * or to NULL when there is no safe Param.
    8492              :  *
    8493              :  * Note that this mechanism intentionally allows just one Param to emit a
    8494              :  * read/write pointer; in case 2, the expression could contain other Params
    8495              :  * referencing the target variable, but those must be treated as read-only.
    8496              :  *
    8497              :  * Also note that we only apply this optimization within simple expressions.
    8498              :  * There's no point in it for non-simple expressions, because the
    8499              :  * exec_run_select code path will flatten any expanded result anyway.
    8500              :  */
    8501              : static void
    8502           65 : exec_check_rw_parameter(PLpgSQL_expr *expr, int paramid)
    8503              : {
    8504           65 :     Expr       *sexpr = expr->expr_simple_expr;
    8505              :     Oid         funcid;
    8506              :     List       *fargs;
    8507              :     Oid         prosupport;
    8508              : 
    8509              :     /* Assume unsafe */
    8510           65 :     expr->expr_rwopt = PLPGSQL_RWOPT_NOPE;
    8511           65 :     expr->expr_rw_param = NULL;
    8512              : 
    8513              :     /* Shouldn't be here for non-simple expression */
    8514              :     Assert(sexpr != NULL);
    8515              : 
    8516              :     /* Param should match the expression's assignment target, too */
    8517              :     Assert(paramid == expr->target_param + 1);
    8518              : 
    8519              :     /*
    8520              :      * If the assignment is to a "local" variable (one whose value won't
    8521              :      * matter anymore if expression evaluation fails), and this Param is the
    8522              :      * only reference to that variable in the expression, then we can
    8523              :      * unconditionally optimize using the "transfer" method.
    8524              :      */
    8525           65 :     if (expr->target_is_local)
    8526              :     {
    8527              :         count_param_references_context context;
    8528              : 
    8529              :         /* See how many references there are, and find one of them */
    8530           65 :         context.paramid = paramid;
    8531           65 :         context.count = 0;
    8532           65 :         context.last_param = NULL;
    8533           65 :         (void) count_param_references((Node *) sexpr, &context);
    8534              : 
    8535              :         /* If we're here, the expr must contain some reference to the var */
    8536              :         Assert(context.count > 0);
    8537              : 
    8538              :         /* If exactly one reference, success! */
    8539           65 :         if (context.count == 1)
    8540              :         {
    8541           61 :             expr->expr_rwopt = PLPGSQL_RWOPT_TRANSFER;
    8542           61 :             expr->expr_rw_param = context.last_param;
    8543           61 :             return;
    8544              :         }
    8545              :     }
    8546              : 
    8547              :     /*
    8548              :      * Otherwise, see if we can trust the expression's top-level function to
    8549              :      * apply the "inplace" method.
    8550              :      *
    8551              :      * Top level of expression must be a simple FuncExpr, OpExpr, or
    8552              :      * SubscriptingRef, else we can't identify which function is relevant. But
    8553              :      * it's okay to look through any RelabelType above that, since that can't
    8554              :      * fail.
    8555              :      */
    8556            4 :     if (IsA(sexpr, RelabelType))
    8557            0 :         sexpr = ((RelabelType *) sexpr)->arg;
    8558            4 :     if (IsA(sexpr, FuncExpr))
    8559              :     {
    8560            0 :         FuncExpr   *fexpr = (FuncExpr *) sexpr;
    8561              : 
    8562            0 :         funcid = fexpr->funcid;
    8563            0 :         fargs = fexpr->args;
    8564              :     }
    8565            4 :     else if (IsA(sexpr, OpExpr))
    8566              :     {
    8567            3 :         OpExpr     *opexpr = (OpExpr *) sexpr;
    8568              : 
    8569            3 :         funcid = opexpr->opfuncid;
    8570            3 :         fargs = opexpr->args;
    8571              :     }
    8572            1 :     else if (IsA(sexpr, SubscriptingRef))
    8573              :     {
    8574            1 :         SubscriptingRef *sbsref = (SubscriptingRef *) sexpr;
    8575              : 
    8576            1 :         funcid = get_typsubscript(sbsref->refcontainertype, NULL);
    8577              : 
    8578              :         /*
    8579              :          * We assume that only the refexpr and refassgnexpr (if any) are
    8580              :          * relevant to the support function's decision.  If that turns out to
    8581              :          * be a bad idea, we could incorporate the subscript expressions into
    8582              :          * the fargs list somehow.
    8583              :          */
    8584            1 :         fargs = list_make2(sbsref->refexpr, sbsref->refassgnexpr);
    8585              :     }
    8586              :     else
    8587            0 :         return;
    8588              : 
    8589              :     /*
    8590              :      * The top-level function must be one that can handle in-place update
    8591              :      * safely.  We allow functions to declare their ability to do that via a
    8592              :      * support function request.
    8593              :      */
    8594            4 :     prosupport = get_func_support(funcid);
    8595            4 :     if (OidIsValid(prosupport))
    8596              :     {
    8597              :         SupportRequestModifyInPlace req;
    8598              :         Param      *param;
    8599              : 
    8600            3 :         req.type = T_SupportRequestModifyInPlace;
    8601            3 :         req.funcid = funcid;
    8602            3 :         req.args = fargs;
    8603            3 :         req.paramid = paramid;
    8604              : 
    8605              :         param = (Param *)
    8606            3 :             DatumGetPointer(OidFunctionCall1(prosupport,
    8607              :                                              PointerGetDatum(&req)));
    8608              : 
    8609            3 :         if (param == NULL)
    8610            0 :             return;             /* support function fails */
    8611              : 
    8612              :         /* Verify support function followed the API */
    8613              :         Assert(IsA(param, Param));
    8614              :         Assert(param->paramkind == PARAM_EXTERN);
    8615              :         Assert(param->paramid == paramid);
    8616              : 
    8617              :         /* Found the Param we want to pass as read/write */
    8618            3 :         expr->expr_rwopt = PLPGSQL_RWOPT_INPLACE;
    8619            3 :         expr->expr_rw_param = param;
    8620            3 :         return;
    8621              :     }
    8622              : }
    8623              : 
    8624              : /*
    8625              :  * Count Params referencing the specified paramid, and return one of them
    8626              :  * if there are any.
    8627              :  *
    8628              :  * We actually only need to distinguish 0, 1, and N references; so we can
    8629              :  * abort the tree traversal as soon as we've found two.
    8630              :  */
    8631              : static bool
    8632          307 : count_param_references(Node *node, count_param_references_context *context)
    8633              : {
    8634          307 :     if (node == NULL)
    8635            1 :         return false;
    8636          306 :     else if (IsA(node, Param))
    8637              :     {
    8638          110 :         Param      *param = (Param *) node;
    8639              : 
    8640          110 :         if (param->paramkind == PARAM_EXTERN &&
    8641          110 :             param->paramid == context->paramid)
    8642              :         {
    8643           69 :             context->last_param = param;
    8644           69 :             if (++(context->count) > 1)
    8645            4 :                 return true;    /* abort tree traversal */
    8646              :         }
    8647          106 :         return false;
    8648              :     }
    8649              :     else
    8650          196 :         return expression_tree_walker(node, count_param_references, context);
    8651              : }
    8652              : 
    8653              : /*
    8654              :  * exec_check_assignable --- is it OK to assign to the indicated datum?
    8655              :  *
    8656              :  * This should match pl_gram.y's check_assignable().
    8657              :  */
    8658              : static void
    8659          181 : exec_check_assignable(PLpgSQL_execstate *estate, int dno)
    8660              : {
    8661              :     PLpgSQL_datum *datum;
    8662              : 
    8663              :     Assert(dno >= 0 && dno < estate->ndatums);
    8664          181 :     datum = estate->datums[dno];
    8665          181 :     switch (datum->dtype)
    8666              :     {
    8667          179 :         case PLPGSQL_DTYPE_VAR:
    8668              :         case PLPGSQL_DTYPE_PROMISE:
    8669              :         case PLPGSQL_DTYPE_REC:
    8670          179 :             if (((PLpgSQL_variable *) datum)->isconst)
    8671            5 :                 ereport(ERROR,
    8672              :                         (errcode(ERRCODE_ERROR_IN_ASSIGNMENT),
    8673              :                          errmsg("variable \"%s\" is declared CONSTANT",
    8674              :                                 ((PLpgSQL_variable *) datum)->refname)));
    8675          174 :             break;
    8676            0 :         case PLPGSQL_DTYPE_ROW:
    8677              :             /* always assignable; member vars were checked at compile time */
    8678            0 :             break;
    8679            2 :         case PLPGSQL_DTYPE_RECFIELD:
    8680              :             /* assignable if parent record is */
    8681            2 :             exec_check_assignable(estate,
    8682              :                                   ((PLpgSQL_recfield *) datum)->recparentno);
    8683            2 :             break;
    8684            0 :         default:
    8685            0 :             elog(ERROR, "unrecognized dtype: %d", datum->dtype);
    8686              :             break;
    8687              :     }
    8688          176 : }
    8689              : 
    8690              : /* ----------
    8691              :  * exec_set_found           Set the global found variable to true/false
    8692              :  * ----------
    8693              :  */
    8694              : static void
    8695        95480 : exec_set_found(PLpgSQL_execstate *estate, bool state)
    8696              : {
    8697              :     PLpgSQL_var *var;
    8698              : 
    8699        95480 :     var = (PLpgSQL_var *) (estate->datums[estate->found_varno]);
    8700              : 
    8701              :     /*
    8702              :      * Use pg_assume() to avoid a spurious warning with some compilers, by
    8703              :      * telling the compiler that the VARATT_IS_EXTERNAL_NON_EXPANDED() branch
    8704              :      * in assign_simple_var() will never be reached when called from here, due
    8705              :      * to "found" being a boolean (i.e. a byvalue type), not a varlena.
    8706              :      */
    8707        95480 :     pg_assume(var->datatype->typlen != -1);
    8708              : 
    8709        95480 :     assign_simple_var(estate, var, BoolGetDatum(state), false, false);
    8710        95480 : }
    8711              : 
    8712              : /*
    8713              :  * plpgsql_create_econtext --- create an eval_econtext for the current function
    8714              :  *
    8715              :  * We may need to create a new shared_simple_eval_estate too, if there's not
    8716              :  * one already for the current transaction.  The EState will be cleaned up at
    8717              :  * transaction end.  Ditto for shared_simple_eval_resowner.
    8718              :  */
    8719              : static void
    8720        65517 : plpgsql_create_econtext(PLpgSQL_execstate *estate)
    8721              : {
    8722              :     SimpleEcontextStackEntry *entry;
    8723              : 
    8724              :     /*
    8725              :      * Create an EState for evaluation of simple expressions, if there's not
    8726              :      * one already in the current transaction.  The EState is made a child of
    8727              :      * TopTransactionContext so it will have the right lifespan.
    8728              :      *
    8729              :      * Note that this path is never taken when beginning a DO block; the
    8730              :      * required EState was already made by plpgsql_inline_handler.  However,
    8731              :      * if the DO block executes COMMIT or ROLLBACK, then we'll come here and
    8732              :      * make a shared EState to use for the rest of the DO block.  That's OK;
    8733              :      * see the comments for shared_simple_eval_estate.  (Note also that a DO
    8734              :      * block will continue to use its private cast hash table for the rest of
    8735              :      * the block.  That's okay for now, but it might cause problems someday.)
    8736              :      */
    8737        65517 :     if (estate->simple_eval_estate == NULL)
    8738              :     {
    8739              :         MemoryContext oldcontext;
    8740              : 
    8741        10340 :         if (shared_simple_eval_estate == NULL)
    8742              :         {
    8743        10336 :             oldcontext = MemoryContextSwitchTo(TopTransactionContext);
    8744        10336 :             shared_simple_eval_estate = CreateExecutorState();
    8745        10336 :             MemoryContextSwitchTo(oldcontext);
    8746              :         }
    8747        10340 :         estate->simple_eval_estate = shared_simple_eval_estate;
    8748              :     }
    8749              : 
    8750              :     /*
    8751              :      * Likewise for the simple-expression resource owner.
    8752              :      */
    8753        65517 :     if (estate->simple_eval_resowner == NULL)
    8754              :     {
    8755        10340 :         if (shared_simple_eval_resowner == NULL)
    8756        10336 :             shared_simple_eval_resowner =
    8757        10336 :                 ResourceOwnerCreate(TopTransactionResourceOwner,
    8758              :                                     "PL/pgSQL simple expressions");
    8759        10340 :         estate->simple_eval_resowner = shared_simple_eval_resowner;
    8760              :     }
    8761              : 
    8762              :     /*
    8763              :      * Create a child econtext for the current function.
    8764              :      */
    8765        65517 :     estate->eval_econtext = CreateExprContext(estate->simple_eval_estate);
    8766              : 
    8767              :     /*
    8768              :      * Make a stack entry so we can clean up the econtext at subxact end.
    8769              :      * Stack entries are kept in TopTransactionContext for simplicity.
    8770              :      */
    8771              :     entry = (SimpleEcontextStackEntry *)
    8772        65517 :         MemoryContextAlloc(TopTransactionContext,
    8773              :                            sizeof(SimpleEcontextStackEntry));
    8774              : 
    8775        65517 :     entry->stack_econtext = estate->eval_econtext;
    8776        65517 :     entry->xact_subxid = GetCurrentSubTransactionId();
    8777              : 
    8778        65517 :     entry->next = simple_econtext_stack;
    8779        65517 :     simple_econtext_stack = entry;
    8780        65517 : }
    8781              : 
    8782              : /*
    8783              :  * plpgsql_destroy_econtext --- destroy function's econtext
    8784              :  *
    8785              :  * We check that it matches the top stack entry, and destroy the stack
    8786              :  * entry along with the context.
    8787              :  */
    8788              : static void
    8789        53944 : plpgsql_destroy_econtext(PLpgSQL_execstate *estate)
    8790              : {
    8791              :     SimpleEcontextStackEntry *next;
    8792              : 
    8793              :     Assert(simple_econtext_stack != NULL);
    8794              :     Assert(simple_econtext_stack->stack_econtext == estate->eval_econtext);
    8795              : 
    8796        53944 :     next = simple_econtext_stack->next;
    8797        53944 :     pfree(simple_econtext_stack);
    8798        53944 :     simple_econtext_stack = next;
    8799              : 
    8800        53944 :     FreeExprContext(estate->eval_econtext, true);
    8801        53944 :     estate->eval_econtext = NULL;
    8802        53944 : }
    8803              : 
    8804              : /*
    8805              :  * plpgsql_xact_cb --- post-transaction-commit-or-abort cleanup
    8806              :  *
    8807              :  * If a simple-expression EState was created in the current transaction,
    8808              :  * it has to be cleaned up.  The same for the simple-expression resowner.
    8809              :  */
    8810              : void
    8811       203457 : plpgsql_xact_cb(XactEvent event, void *arg)
    8812              : {
    8813              :     /*
    8814              :      * If we are doing a clean transaction shutdown, free the EState and tell
    8815              :      * the resowner to release whatever plancache references it has, so that
    8816              :      * all remaining resources will be released correctly.  (We don't need to
    8817              :      * actually delete the resowner here; deletion of the
    8818              :      * TopTransactionResourceOwner will take care of that.)
    8819              :      *
    8820              :      * In an abort, we expect the regular abort recovery procedures to release
    8821              :      * everything of interest, so just clear our pointers.
    8822              :      */
    8823       203457 :     if (event == XACT_EVENT_COMMIT ||
    8824       106467 :         event == XACT_EVENT_PARALLEL_COMMIT ||
    8825              :         event == XACT_EVENT_PREPARE)
    8826              :     {
    8827        97008 :         simple_econtext_stack = NULL;
    8828              : 
    8829        97008 :         if (shared_simple_eval_estate)
    8830         9420 :             FreeExecutorState(shared_simple_eval_estate);
    8831        97008 :         shared_simple_eval_estate = NULL;
    8832        97008 :         if (shared_simple_eval_resowner)
    8833         9420 :             ReleaseAllPlanCacheRefsInOwner(shared_simple_eval_resowner);
    8834        97008 :         shared_simple_eval_resowner = NULL;
    8835              :     }
    8836       106449 :     else if (event == XACT_EVENT_ABORT ||
    8837              :              event == XACT_EVENT_PARALLEL_ABORT)
    8838              :     {
    8839         9389 :         simple_econtext_stack = NULL;
    8840         9389 :         shared_simple_eval_estate = NULL;
    8841         9389 :         shared_simple_eval_resowner = NULL;
    8842              :     }
    8843       203457 : }
    8844              : 
    8845              : /*
    8846              :  * plpgsql_subxact_cb --- post-subtransaction-commit-or-abort cleanup
    8847              :  *
    8848              :  * Make sure any simple-expression econtexts created in the current
    8849              :  * subtransaction get cleaned up.  We have to do this explicitly because
    8850              :  * no other code knows which econtexts belong to which level of subxact.
    8851              :  */
    8852              : void
    8853        23781 : plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid,
    8854              :                    SubTransactionId parentSubid, void *arg)
    8855              : {
    8856        23781 :     if (event == SUBXACT_EVENT_COMMIT_SUB || event == SUBXACT_EVENT_ABORT_SUB)
    8857              :     {
    8858        18578 :         while (simple_econtext_stack != NULL &&
    8859        17710 :                simple_econtext_stack->xact_subxid == mySubid)
    8860              :         {
    8861              :             SimpleEcontextStackEntry *next;
    8862              : 
    8863         8958 :             FreeExprContext(simple_econtext_stack->stack_econtext,
    8864              :                             (event == SUBXACT_EVENT_COMMIT_SUB));
    8865         8958 :             next = simple_econtext_stack->next;
    8866         8958 :             pfree(simple_econtext_stack);
    8867         8958 :             simple_econtext_stack = next;
    8868              :         }
    8869              :     }
    8870        23781 : }
    8871              : 
    8872              : /*
    8873              :  * assign_simple_var --- assign a new value to any VAR datum.
    8874              :  *
    8875              :  * This should be the only mechanism for assignment to simple variables,
    8876              :  * lest we do the release of the old value incorrectly (not to mention
    8877              :  * the detoasting business).
    8878              :  */
    8879              : static void
    8880       323178 : assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var,
    8881              :                   Datum newvalue, bool isnull, bool freeable)
    8882              : {
    8883              :     Assert(var->dtype == PLPGSQL_DTYPE_VAR ||
    8884              :            var->dtype == PLPGSQL_DTYPE_PROMISE);
    8885              : 
    8886              :     /*
    8887              :      * In non-atomic contexts, we do not want to store TOAST pointers in
    8888              :      * variables, because such pointers might become stale after a commit.
    8889              :      * Forcibly detoast in such cases.  We don't want to detoast (flatten)
    8890              :      * expanded objects, however; those should be OK across a transaction
    8891              :      * boundary since they're just memory-resident objects.  (Elsewhere in
    8892              :      * this module, operations on expanded records likewise need to request
    8893              :      * detoasting of record fields when !estate->atomic.  Expanded arrays are
    8894              :      * not a problem since all array entries are always detoasted.)
    8895              :      */
    8896       352902 :     if (!estate->atomic && !isnull && var->datatype->typlen == -1 &&
    8897        29724 :         VARATT_IS_EXTERNAL_NON_EXPANDED(DatumGetPointer(newvalue)))
    8898              :     {
    8899              :         MemoryContext oldcxt;
    8900              :         Datum       detoasted;
    8901              : 
    8902              :         /*
    8903              :          * Do the detoasting in the eval_mcontext to avoid long-term leakage
    8904              :          * of whatever memory toast fetching might leak.  Then we have to copy
    8905              :          * the detoasted datum to the function's main context, which is a
    8906              :          * pain, but there's little choice.
    8907              :          */
    8908            8 :         oldcxt = MemoryContextSwitchTo(get_eval_mcontext(estate));
    8909            8 :         detoasted = PointerGetDatum(detoast_external_attr((varlena *) DatumGetPointer(newvalue)));
    8910            8 :         MemoryContextSwitchTo(oldcxt);
    8911              :         /* Now's a good time to not leak the input value if it's freeable */
    8912            8 :         if (freeable)
    8913            8 :             pfree(DatumGetPointer(newvalue));
    8914              :         /* Once we copy the value, it's definitely freeable */
    8915            8 :         newvalue = datumCopy(detoasted, false, -1);
    8916            8 :         freeable = true;
    8917              :         /* Can't clean up eval_mcontext here, but it'll happen before long */
    8918              :     }
    8919              : 
    8920              :     /* Free the old value if needed */
    8921       323178 :     if (var->freeval)
    8922              :     {
    8923        63954 :         if (DatumIsReadWriteExpandedObject(var->value,
    8924              :                                            var->isnull,
    8925              :                                            var->datatype->typlen))
    8926         4747 :             DeleteExpandedObject(var->value);
    8927              :         else
    8928        59207 :             pfree(DatumGetPointer(var->value));
    8929              :     }
    8930              :     /* Assign new value to datum */
    8931       323178 :     var->value = newvalue;
    8932       323178 :     var->isnull = isnull;
    8933       323178 :     var->freeval = freeable;
    8934              : 
    8935              :     /*
    8936              :      * If it's a promise variable, then either we just assigned the promised
    8937              :      * value, or the user explicitly assigned an overriding value.  Either
    8938              :      * way, cancel the promise.
    8939              :      */
    8940       323178 :     var->promise = PLPGSQL_PROMISE_NONE;
    8941       323178 : }
    8942              : 
    8943              : /*
    8944              :  * free old value of a text variable and assign new value from C string
    8945              :  */
    8946              : static void
    8947        16591 : assign_text_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, const char *str)
    8948              : {
    8949        16591 :     assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
    8950        16591 : }
    8951              : 
    8952              : /*
    8953              :  * assign_record_var --- assign a new value to any REC datum.
    8954              :  */
    8955              : static void
    8956         4479 : assign_record_var(PLpgSQL_execstate *estate, PLpgSQL_rec *rec,
    8957              :                   ExpandedRecordHeader *erh)
    8958              : {
    8959              :     Assert(rec->dtype == PLPGSQL_DTYPE_REC);
    8960              : 
    8961              :     /* Transfer new record object into datum_context */
    8962         4479 :     TransferExpandedRecord(erh, estate->datum_context);
    8963              : 
    8964              :     /* Free the old value ... */
    8965         4479 :     if (rec->erh)
    8966         1230 :         DeleteExpandedObject(ExpandedRecordGetDatum(rec->erh));
    8967              : 
    8968              :     /* ... and install the new */
    8969         4479 :     rec->erh = erh;
    8970         4479 : }
    8971              : 
    8972              : /*
    8973              :  * exec_eval_using_params --- evaluate params of USING clause
    8974              :  *
    8975              :  * The result data structure is created in the stmt_mcontext, and should
    8976              :  * be freed by resetting that context.
    8977              :  */
    8978              : static ParamListInfo
    8979        17714 : exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
    8980              : {
    8981              :     ParamListInfo paramLI;
    8982              :     int         nargs;
    8983              :     MemoryContext stmt_mcontext;
    8984              :     MemoryContext oldcontext;
    8985              :     int         i;
    8986              :     ListCell   *lc;
    8987              : 
    8988              :     /* Fast path for no parameters: we can just return NULL */
    8989        17714 :     if (params == NIL)
    8990        17417 :         return NULL;
    8991              : 
    8992          297 :     nargs = list_length(params);
    8993          297 :     stmt_mcontext = get_stmt_mcontext(estate);
    8994          297 :     oldcontext = MemoryContextSwitchTo(stmt_mcontext);
    8995          297 :     paramLI = makeParamList(nargs);
    8996          297 :     MemoryContextSwitchTo(oldcontext);
    8997              : 
    8998          297 :     i = 0;
    8999          879 :     foreach(lc, params)
    9000              :     {
    9001          582 :         PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
    9002          582 :         ParamExternData *prm = &paramLI->params[i];
    9003              :         int32       ppdtypmod;
    9004              : 
    9005              :         /*
    9006              :          * Always mark params as const, since we only use the result with
    9007              :          * one-shot plans.
    9008              :          */
    9009          582 :         prm->pflags = PARAM_FLAG_CONST;
    9010              : 
    9011          582 :         prm->value = exec_eval_expr(estate, param,
    9012              :                                     &prm->isnull,
    9013              :                                     &prm->ptype,
    9014              :                                     &ppdtypmod);
    9015              : 
    9016          582 :         oldcontext = MemoryContextSwitchTo(stmt_mcontext);
    9017              : 
    9018          582 :         if (prm->ptype == UNKNOWNOID)
    9019              :         {
    9020              :             /*
    9021              :              * Treat 'unknown' parameters as text, since that's what most
    9022              :              * people would expect.  The SPI functions can coerce unknown
    9023              :              * constants in a more intelligent way, but not unknown Params.
    9024              :              * This code also takes care of copying into the right context.
    9025              :              * Note we assume 'unknown' has the representation of C-string.
    9026              :              */
    9027            0 :             prm->ptype = TEXTOID;
    9028            0 :             if (!prm->isnull)
    9029            0 :                 prm->value = CStringGetTextDatum(DatumGetCString(prm->value));
    9030              :         }
    9031              :         /* pass-by-ref non null values must be copied into stmt_mcontext */
    9032          582 :         else if (!prm->isnull)
    9033              :         {
    9034              :             int16       typLen;
    9035              :             bool        typByVal;
    9036              : 
    9037          582 :             get_typlenbyval(prm->ptype, &typLen, &typByVal);
    9038          582 :             if (!typByVal)
    9039          554 :                 prm->value = datumCopy(prm->value, typByVal, typLen);
    9040              :         }
    9041              : 
    9042          582 :         MemoryContextSwitchTo(oldcontext);
    9043              : 
    9044          582 :         exec_eval_cleanup(estate);
    9045              : 
    9046          582 :         i++;
    9047              :     }
    9048              : 
    9049          297 :     return paramLI;
    9050              : }
    9051              : 
    9052              : /*
    9053              :  * Open portal for dynamic query
    9054              :  *
    9055              :  * Caution: this resets the stmt_mcontext at exit.  We might eventually need
    9056              :  * to move that responsibility to the callers, but currently no caller needs
    9057              :  * to have statement-lifetime temp data that survives past this, so it's
    9058              :  * simpler to do it here.
    9059              :  */
    9060              : static Portal
    9061         6399 : exec_dynquery_with_params(PLpgSQL_execstate *estate,
    9062              :                           PLpgSQL_expr *dynquery,
    9063              :                           List *params,
    9064              :                           const char *portalname,
    9065              :                           int cursorOptions)
    9066              : {
    9067              :     Portal      portal;
    9068              :     Datum       query;
    9069              :     bool        isnull;
    9070              :     Oid         restype;
    9071              :     int32       restypmod;
    9072              :     char       *querystr;
    9073              :     SPIParseOpenOptions options;
    9074         6399 :     MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
    9075              : 
    9076              :     /*
    9077              :      * Evaluate the string expression after the EXECUTE keyword. Its result is
    9078              :      * the querystring we have to execute.
    9079              :      */
    9080         6399 :     query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
    9081         6399 :     if (isnull)
    9082            0 :         ereport(ERROR,
    9083              :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    9084              :                  errmsg("query string argument of EXECUTE is null")));
    9085              : 
    9086              :     /* Get the C-String representation */
    9087         6399 :     querystr = convert_value_to_string(estate, query, restype);
    9088              : 
    9089              :     /* copy it into the stmt_mcontext before we clean up */
    9090         6399 :     querystr = MemoryContextStrdup(stmt_mcontext, querystr);
    9091              : 
    9092         6399 :     exec_eval_cleanup(estate);
    9093              : 
    9094              :     /*
    9095              :      * Open an implicit cursor for the query.  We use SPI_cursor_parse_open
    9096              :      * even when there are no params, because this avoids making and freeing
    9097              :      * one copy of the plan.
    9098              :      */
    9099         6399 :     memset(&options, 0, sizeof(options));
    9100         6399 :     options.params = exec_eval_using_params(estate, params);
    9101         6399 :     options.cursorOptions = cursorOptions;
    9102         6399 :     options.read_only = estate->readonly_func;
    9103              : 
    9104         6399 :     portal = SPI_cursor_parse_open(portalname, querystr, &options);
    9105              : 
    9106         6399 :     if (portal == NULL)
    9107            0 :         elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
    9108              :              querystr, SPI_result_code_string(SPI_result));
    9109              : 
    9110              :     /* Release transient data */
    9111         6399 :     MemoryContextReset(stmt_mcontext);
    9112              : 
    9113         6399 :     return portal;
    9114              : }
    9115              : 
    9116              : /*
    9117              :  * Return a formatted string with information about an expression's parameters,
    9118              :  * or NULL if the expression does not take any parameters.
    9119              :  * The result is in the eval_mcontext.
    9120              :  */
    9121              : static char *
    9122           20 : format_expr_params(PLpgSQL_execstate *estate,
    9123              :                    const PLpgSQL_expr *expr)
    9124              : {
    9125              :     int         paramno;
    9126              :     int         dno;
    9127              :     StringInfoData paramstr;
    9128              :     MemoryContext oldcontext;
    9129              : 
    9130           20 :     if (!expr->paramnos)
    9131            4 :         return NULL;
    9132              : 
    9133           16 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    9134              : 
    9135           16 :     initStringInfo(&paramstr);
    9136           16 :     paramno = 0;
    9137           16 :     dno = -1;
    9138           48 :     while ((dno = bms_next_member(expr->paramnos, dno)) >= 0)
    9139              :     {
    9140              :         Datum       paramdatum;
    9141              :         Oid         paramtypeid;
    9142              :         bool        paramisnull;
    9143              :         int32       paramtypmod;
    9144              :         PLpgSQL_var *curvar;
    9145              : 
    9146           32 :         curvar = (PLpgSQL_var *) estate->datums[dno];
    9147              : 
    9148           32 :         exec_eval_datum(estate, (PLpgSQL_datum *) curvar,
    9149              :                         &paramtypeid, &paramtypmod,
    9150              :                         &paramdatum, &paramisnull);
    9151              : 
    9152           32 :         appendStringInfo(&paramstr, "%s%s = ",
    9153              :                          paramno > 0 ? ", " : "",
    9154              :                          curvar->refname);
    9155              : 
    9156           32 :         if (paramisnull)
    9157            0 :             appendStringInfoString(&paramstr, "NULL");
    9158              :         else
    9159           32 :             appendStringInfoStringQuoted(&paramstr,
    9160           32 :                                          convert_value_to_string(estate,
    9161              :                                                                  paramdatum,
    9162              :                                                                  paramtypeid),
    9163              :                                          -1);
    9164              : 
    9165           32 :         paramno++;
    9166              :     }
    9167              : 
    9168           16 :     MemoryContextSwitchTo(oldcontext);
    9169              : 
    9170           16 :     return paramstr.data;
    9171              : }
    9172              : 
    9173              : /*
    9174              :  * Return a formatted string with information about the parameter values,
    9175              :  * or NULL if there are no parameters.
    9176              :  * The result is in the eval_mcontext.
    9177              :  */
    9178              : static char *
    9179           12 : format_preparedparamsdata(PLpgSQL_execstate *estate,
    9180              :                           ParamListInfo paramLI)
    9181              : {
    9182              :     int         paramno;
    9183              :     StringInfoData paramstr;
    9184              :     MemoryContext oldcontext;
    9185              : 
    9186           12 :     if (!paramLI)
    9187            4 :         return NULL;
    9188              : 
    9189            8 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    9190              : 
    9191            8 :     initStringInfo(&paramstr);
    9192           20 :     for (paramno = 0; paramno < paramLI->numParams; paramno++)
    9193              :     {
    9194           12 :         ParamExternData *prm = &paramLI->params[paramno];
    9195              : 
    9196              :         /*
    9197              :          * Note: for now, this is only used on ParamListInfos produced by
    9198              :          * exec_eval_using_params(), so we don't worry about invoking the
    9199              :          * paramFetch hook or skipping unused parameters.
    9200              :          */
    9201           12 :         appendStringInfo(&paramstr, "%s$%d = ",
    9202              :                          paramno > 0 ? ", " : "",
    9203              :                          paramno + 1);
    9204              : 
    9205           12 :         if (prm->isnull)
    9206            0 :             appendStringInfoString(&paramstr, "NULL");
    9207              :         else
    9208           12 :             appendStringInfoStringQuoted(&paramstr,
    9209           12 :                                          convert_value_to_string(estate,
    9210              :                                                                  prm->value,
    9211              :                                                                  prm->ptype),
    9212              :                                          -1);
    9213              :     }
    9214              : 
    9215            8 :     MemoryContextSwitchTo(oldcontext);
    9216              : 
    9217            8 :     return paramstr.data;
    9218              : }
        

Generated by: LCOV version 2.0-1