LCOV - code coverage report
Current view: top level - src/pl/plpgsql/src - pl_exec.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 91.0 % 2753 2506
Test Date: 2026-07-26 02:15:44 Functions: 100.0 % 99 99
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 68.4 % 1916 1310

             Branch data     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                 :       45982 : 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                 :       45982 :     plpgsql_estate_setup(&estate, func, (ReturnSetInfo *) fcinfo->resultinfo,
     509                 :             :                          simple_eval_estate, simple_eval_resowner);
     510                 :       45982 :     estate.procedure_resowner = procedure_resowner;
     511                 :       45982 :     estate.atomic = atomic;
     512                 :             : 
     513                 :             :     /*
     514                 :             :      * Setup error traceback support for ereport()
     515                 :             :      */
     516                 :       45982 :     plerrcontext.callback = plpgsql_exec_error_callback;
     517                 :       45982 :     plerrcontext.arg = &estate;
     518                 :       45982 :     plerrcontext.previous = error_context_stack;
     519                 :       45982 :     error_context_stack = &plerrcontext;
     520                 :             : 
     521                 :             :     /*
     522                 :             :      * Make local execution copies of all the datums
     523                 :             :      */
     524                 :       45982 :     estate.err_text = gettext_noop("during initialization of execution state");
     525                 :       45982 :     copy_plpgsql_datums(&estate, func);
     526                 :             : 
     527                 :             :     /*
     528                 :             :      * Store the actual call argument values into the appropriate variables
     529                 :             :      */
     530                 :       45982 :     estate.err_text = gettext_noop("while storing call arguments into local variables");
     531         [ +  + ]:      104463 :     for (i = 0; i < func->fn_nargs; i++)
     532                 :             :     {
     533                 :       58481 :         int         n = func->fn_argvarnos[i];
     534                 :             : 
     535      [ +  +  - ]:       58481 :         switch (estate.datums[n]->dtype)
     536                 :             :         {
     537                 :       57410 :             case PLPGSQL_DTYPE_VAR:
     538                 :             :                 {
     539                 :       57410 :                     PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[n];
     540                 :             : 
     541                 :       57410 :                     assign_simple_var(&estate, var,
     542                 :             :                                       fcinfo->args[i].value,
     543                 :       57410 :                                       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   [ +  +  +  + ]:       57410 :                     if (!var->isnull && var->datatype->typlen == -1)
     563                 :             :                     {
     564         [ +  + ]:       20862 :                         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         [ +  + ]:       20858 :                         else if (VARATT_IS_EXTERNAL_EXPANDED_RO(DatumGetPointer(var->value)))
     574                 :             :                         {
     575                 :             :                             /* R/O pointer, keep it as-is until assigned to */
     576                 :             :                         }
     577         [ +  + ]:       20814 :                         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                 :       57410 :                 break;
     590                 :             : 
     591                 :        1071 :             case PLPGSQL_DTYPE_REC:
     592                 :             :                 {
     593                 :        1071 :                     PLpgSQL_rec *rec = (PLpgSQL_rec *) estate.datums[n];
     594                 :             : 
     595         [ +  + ]:        1071 :                     if (!fcinfo->args[i].isnull)
     596                 :             :                     {
     597                 :             :                         /* Assign row value from composite datum */
     598                 :        1032 :                         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                 :        1071 :                     exec_eval_cleanup(&estate);
     610                 :             :                 }
     611                 :        1071 :                 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                 :       45982 :     estate.err_text = gettext_noop("during function entry");
     620                 :             : 
     621                 :             :     /*
     622                 :             :      * Set the magic variable FOUND to false
     623                 :             :      */
     624                 :       45982 :     exec_set_found(&estate, false);
     625                 :             : 
     626                 :             :     /*
     627                 :             :      * Let the instrumentation plugin peek at this function
     628                 :             :      */
     629   [ -  +  -  - ]:       45982 :     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                 :       45982 :     estate.err_text = NULL;
     636                 :       45982 :     rc = exec_toplevel_block(&estate, func->action);
     637         [ +  + ]:       45433 :     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                 :       45429 :     estate.err_text = gettext_noop("while casting return value to function's return type");
     649                 :             : 
     650                 :       45429 :     fcinfo->isnull = estate.retisnull;
     651                 :             : 
     652         [ +  + ]:       45429 :     if (estate.retisset)
     653                 :             :     {
     654                 :        2460 :         ReturnSetInfo *rsi = estate.rsi;
     655                 :             : 
     656                 :             :         /* Check caller can handle a set result */
     657   [ +  -  -  + ]:        2460 :         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         [ -  + ]:        2460 :         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                 :        2460 :         rsi->returnMode = SFRM_Materialize;
     668                 :             : 
     669                 :             :         /* If we produced any tuples, send back the result */
     670         [ +  + ]:        2460 :         if (estate.tuple_store)
     671                 :             :         {
     672                 :             :             MemoryContext oldcxt;
     673                 :             : 
     674                 :        2448 :             rsi->setResult = estate.tuple_store;
     675                 :        2448 :             oldcxt = MemoryContextSwitchTo(estate.tuple_store_cxt);
     676                 :        2448 :             rsi->setDesc = CreateTupleDescCopy(estate.tuple_store_desc);
     677                 :        2448 :             MemoryContextSwitchTo(oldcxt);
     678                 :             :         }
     679                 :        2460 :         estate.retval = (Datum) 0;
     680                 :        2460 :         fcinfo->isnull = true;
     681                 :             :     }
     682         [ +  + ]:       42969 :     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         [ +  + ]:       42233 :         if (estate.retistuple)
     691                 :             :         {
     692                 :             :             /* Don't need coercion if rowtype is known to match */
     693         [ +  + ]:        3483 :             if (func->fn_rettype == estate.rettype &&
     694         [ +  + ]:        3444 :                 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   [ +  +  +  - ]:        3341 :                 switch (get_call_result_type(fcinfo, &resultTypeId, &tupdesc))
     719                 :             :                 {
     720                 :        3297 :                     case TYPEFUNC_COMPOSITE:
     721                 :             :                         /* got the expected result rowtype, now coerce it */
     722                 :        3297 :                         coerce_function_result_tuple(&estate, tupdesc);
     723                 :        3281 :                         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                 :       38750 :             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   [ +  -  +  + ]:       38728 :             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         [ +  + ]:         736 :         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                 :       45386 :     estate.err_text = gettext_noop("during function exit");
     793                 :             : 
     794                 :             :     /*
     795                 :             :      * Let the instrumentation plugin peek at this function
     796                 :             :      */
     797   [ -  +  -  - ]:       45386 :     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                 :       45386 :     plpgsql_destroy_econtext(&estate);
     802                 :       45386 :     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                 :       45386 :     error_context_stack = plerrcontext.previous;
     809                 :             : 
     810                 :             :     /*
     811                 :             :      * Return the function's result
     812                 :             :      */
     813                 :       45386 :     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                 :        3305 : 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         [ +  + ]:        3305 :     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                 :        3279 :         retdesc = deconstruct_composite_datum(estate->retval, &tmptup);
     906                 :        3279 :         rettup = &tmptup;
     907                 :             : 
     908                 :             :         /* check rowtype compatibility */
     909                 :        3279 :         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         [ +  + ]:        3269 :         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                 :        3269 :         estate->retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
     922                 :             : 
     923                 :             :         /* no need to free map, we're about to return anyway */
     924                 :             : 
     925         [ +  + ]:        3269 :         ReleaseTupleDesc(retdesc);
     926                 :             :     }
     927                 :        3289 : }
     928                 :             : 
     929                 :             : 
     930                 :             : /* ----------
     931                 :             :  * plpgsql_exec_trigger     Called by the call handler for
     932                 :             :  *              trigger execution.
     933                 :             :  * ----------
     934                 :             :  */
     935                 :             : HeapTuple
     936                 :       10368 : 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                 :       10368 :     plpgsql_estate_setup(&estate, func, NULL, NULL, NULL);
     951                 :       10368 :     estate.trigdata = trigdata;
     952                 :             : 
     953                 :             :     /*
     954                 :             :      * Setup error traceback support for ereport()
     955                 :             :      */
     956                 :       10368 :     plerrcontext.callback = plpgsql_exec_error_callback;
     957                 :       10368 :     plerrcontext.arg = &estate;
     958                 :       10368 :     plerrcontext.previous = error_context_stack;
     959                 :       10368 :     error_context_stack = &plerrcontext;
     960                 :             : 
     961                 :             :     /*
     962                 :             :      * Make local execution copies of all the datums
     963                 :             :      */
     964                 :       10368 :     estate.err_text = gettext_noop("during initialization of execution state");
     965                 :       10368 :     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                 :       10368 :     tupdesc = RelationGetDescr(trigdata->tg_relation);
     978                 :             : 
     979                 :       10368 :     rec_new = (PLpgSQL_rec *) (estate.datums[func->new_varno]);
     980                 :       10368 :     rec_old = (PLpgSQL_rec *) (estate.datums[func->old_varno]);
     981                 :             : 
     982                 :       10368 :     rec_new->erh = make_expanded_record_from_tupdesc(tupdesc,
     983                 :             :                                                      estate.datum_context);
     984                 :       10368 :     rec_old->erh = make_expanded_record_from_exprecord(rec_new->erh,
     985                 :             :                                                        estate.datum_context);
     986                 :             : 
     987         [ +  + ]:       10368 :     if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
     988                 :             :     {
     989                 :             :         /*
     990                 :             :          * Per-statement triggers don't use OLD/NEW variables
     991                 :             :          */
     992                 :             :     }
     993         [ +  + ]:        9276 :     else if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
     994                 :             :     {
     995                 :        4806 :         expanded_record_set_tuple(rec_new->erh, trigdata->tg_trigtuple,
     996                 :             :                                   false, false);
     997                 :             :     }
     998         [ +  + ]:        4470 :     else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
     999                 :             :     {
    1000                 :        4124 :         expanded_record_set_tuple(rec_new->erh, trigdata->tg_newtuple,
    1001                 :             :                                   false, false);
    1002                 :        4124 :         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   [ +  +  +  + ]:        4124 :         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         [ +  - ]:         346 :     else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
    1026                 :             :     {
    1027                 :         346 :         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                 :       10368 :     rc = SPI_register_trigger_data(trigdata);
    1035                 :             :     Assert(rc >= 0);
    1036                 :             : 
    1037                 :       10368 :     estate.err_text = gettext_noop("during function entry");
    1038                 :             : 
    1039                 :             :     /*
    1040                 :             :      * Set the magic variable FOUND to false
    1041                 :             :      */
    1042                 :       10368 :     exec_set_found(&estate, false);
    1043                 :             : 
    1044                 :             :     /*
    1045                 :             :      * Let the instrumentation plugin peek at this function
    1046                 :             :      */
    1047   [ -  +  -  - ]:       10368 :     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                 :       10368 :     estate.err_text = NULL;
    1054                 :       10368 :     rc = exec_toplevel_block(&estate, func->action);
    1055         [ -  + ]:       10230 :     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                 :       10230 :     estate.err_text = gettext_noop("during function exit");
    1064                 :             : 
    1065         [ -  + ]:       10230 :     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   [ +  +  +  + ]:       10230 :     if (estate.retisnull || !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
    1081                 :        1934 :         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         [ +  + ]:        8296 :         if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(estate.retval)))
    1092                 :             :         {
    1093                 :        8294 :             ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(estate.retval);
    1094                 :             : 
    1095                 :             :             Assert(erh->er_magic == ER_MAGIC);
    1096                 :             : 
    1097                 :             :             /* Extract HeapTuple and TupleDesc */
    1098                 :        8294 :             rettup = expanded_record_get_tuple(erh);
    1099                 :             :             Assert(rettup);
    1100                 :        8294 :             retdesc = expanded_record_get_tupdesc(erh);
    1101                 :             : 
    1102         [ +  + ]:        8294 :             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         [ +  + ]:        8294 :             if (rettup != trigdata->tg_newtuple &&
    1121         [ +  + ]:        5293 :                 rettup != trigdata->tg_trigtuple)
    1122                 :        1374 :                 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   [ -  +  -  - ]:       10230 :     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                 :       10230 :     plpgsql_destroy_econtext(&estate);
    1156                 :       10230 :     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                 :       10230 :     error_context_stack = plerrcontext.previous;
    1163                 :             : 
    1164                 :             :     /*
    1165                 :             :      * Return the trigger's result
    1166                 :             :      */
    1167                 :       10230 :     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                 :        1182 : 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                 :        1182 :     plpgsql_estate_setup(&estate, func, NULL, NULL, NULL);
    1186                 :        1182 :     estate.evtrigdata = trigdata;
    1187                 :             : 
    1188                 :             :     /*
    1189                 :             :      * Setup error traceback support for ereport()
    1190                 :             :      */
    1191                 :        1182 :     plerrcontext.callback = plpgsql_exec_error_callback;
    1192                 :        1182 :     plerrcontext.arg = &estate;
    1193                 :        1182 :     plerrcontext.previous = error_context_stack;
    1194                 :        1182 :     error_context_stack = &plerrcontext;
    1195                 :             : 
    1196                 :             :     /*
    1197                 :             :      * Make local execution copies of all the datums
    1198                 :             :      */
    1199                 :        1182 :     estate.err_text = gettext_noop("during initialization of execution state");
    1200                 :        1182 :     copy_plpgsql_datums(&estate, func);
    1201                 :             : 
    1202                 :             :     /*
    1203                 :             :      * Let the instrumentation plugin peek at this function
    1204                 :             :      */
    1205   [ -  +  -  - ]:        1182 :     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                 :        1182 :     estate.err_text = NULL;
    1212                 :        1182 :     rc = exec_toplevel_block(&estate, func->action);
    1213         [ -  + ]:        1166 :     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                 :        1166 :     estate.err_text = gettext_noop("during function exit");
    1222                 :             : 
    1223                 :             :     /*
    1224                 :             :      * Let the instrumentation plugin peek at this function
    1225                 :             :      */
    1226   [ -  +  -  - ]:        1166 :     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                 :        1166 :     plpgsql_destroy_econtext(&estate);
    1231                 :        1166 :     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                 :        1166 :     error_context_stack = plerrcontext.previous;
    1238                 :        1166 : }
    1239                 :             : 
    1240                 :             : /*
    1241                 :             :  * error context callback to let us supply a call-stack traceback
    1242                 :             :  */
    1243                 :             : static void
    1244                 :       15960 : plpgsql_exec_error_callback(void *arg)
    1245                 :             : {
    1246                 :       15960 :     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         [ +  + ]:       15960 :     if (estate->err_var != NULL)
    1256                 :          34 :         err_lineno = estate->err_var->lineno;
    1257         [ +  + ]:       15926 :     else if (estate->err_stmt != NULL)
    1258                 :       15879 :         err_lineno = estate->err_stmt->lineno;
    1259                 :             :     else
    1260                 :          47 :         err_lineno = 0;
    1261                 :             : 
    1262         [ +  + ]:       15960 :     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         [ +  + ]:          77 :         if (err_lineno > 0)
    1271                 :             :         {
    1272                 :             :             /*
    1273                 :             :              * translator: last %s is a phrase such as "during statement block
    1274                 :             :              * local variable initialization"
    1275                 :             :              */
    1276                 :          34 :             errcontext("PL/pgSQL function %s line %d %s",
    1277                 :          34 :                        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   [ +  +  +  - ]:       15883 :     else if (estate->err_stmt != NULL && err_lineno > 0)
    1293                 :             :     {
    1294                 :             :         /* translator: last %s is a plpgsql statement type name */
    1295                 :       15879 :         errcontext("PL/pgSQL function %s line %d at %s",
    1296                 :       15879 :                    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                 :       15960 : }
    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                 :           6 : plpgsql_execsql_error_callback(void *arg)
    1314                 :             : {
    1315                 :           6 :     PLpgSQL_expr *expr = (PLpgSQL_expr *) arg;
    1316                 :           6 :     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                 :           6 :     syntaxerrposition = geterrposition();
    1324         [ -  + ]:           6 :     if (syntaxerrposition > 0)
    1325                 :             :     {
    1326                 :           0 :         errposition(0);
    1327                 :           0 :         internalerrposition(syntaxerrposition);
    1328                 :           0 :         internalerrquery(query);
    1329                 :             :     }
    1330                 :             :     else
    1331                 :             :     {
    1332                 :           6 :         errcontext("SQL statement \"%s\"", query);
    1333                 :             :     }
    1334                 :           6 : }
    1335                 :             : 
    1336                 :             : 
    1337                 :             : /* ----------
    1338                 :             :  * Support function for initializing local execution variables
    1339                 :             :  * ----------
    1340                 :             :  */
    1341                 :             : static void
    1342                 :       57532 : copy_plpgsql_datums(PLpgSQL_execstate *estate,
    1343                 :             :                     PLpgSQL_function *func)
    1344                 :             : {
    1345                 :       57532 :     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                 :       57532 :     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                 :       57532 :     workspace = palloc(func->copiable_size);
    1360                 :       57532 :     ws_next = workspace;
    1361                 :             : 
    1362                 :             :     /* Fill datum-pointer array, copying datums into workspace as needed */
    1363                 :       57532 :     indatums = func->datums;
    1364                 :       57532 :     outdatums = estate->datums;
    1365         [ +  + ]:      384543 :     for (i = 0; i < ndatums; i++)
    1366                 :             :     {
    1367                 :      327011 :         PLpgSQL_datum *indatum = indatums[i];
    1368                 :             :         PLpgSQL_datum *outdatum;
    1369                 :             : 
    1370                 :             :         /* This must agree with plpgsql_finish_datums on what is copiable */
    1371   [ +  +  +  - ]:      327011 :         switch (indatum->dtype)
    1372                 :             :         {
    1373                 :      262991 :             case PLPGSQL_DTYPE_VAR:
    1374                 :             :             case PLPGSQL_DTYPE_PROMISE:
    1375                 :      262991 :                 outdatum = (PLpgSQL_datum *) ws_next;
    1376                 :      262991 :                 memcpy(outdatum, indatum, sizeof(PLpgSQL_var));
    1377                 :      262991 :                 ws_next += MAXALIGN(sizeof(PLpgSQL_var));
    1378                 :      262991 :                 break;
    1379                 :             : 
    1380                 :       25223 :             case PLPGSQL_DTYPE_REC:
    1381                 :       25223 :                 outdatum = (PLpgSQL_datum *) ws_next;
    1382                 :       25223 :                 memcpy(outdatum, indatum, sizeof(PLpgSQL_rec));
    1383                 :       25223 :                 ws_next += MAXALIGN(sizeof(PLpgSQL_rec));
    1384                 :       25223 :                 break;
    1385                 :             : 
    1386                 :       38797 :             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                 :       38797 :                 outdatum = indatum;
    1395                 :       38797 :                 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                 :      327011 :         outdatums[i] = outdatum;
    1404                 :             :     }
    1405                 :             : 
    1406                 :             :     Assert(ws_next == workspace + func->copiable_size);
    1407                 :       57532 : }
    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                 :       16864 : plpgsql_fulfill_promise(PLpgSQL_execstate *estate,
    1416                 :             :                         PLpgSQL_var *var)
    1417                 :             : {
    1418                 :             :     MemoryContext oldcontext;
    1419                 :             : 
    1420         [ +  + ]:       16864 :     if (var->promise == PLPGSQL_PROMISE_NONE)
    1421                 :        5117 :         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                 :       11747 :     oldcontext = MemoryContextSwitchTo(estate->datum_context);
    1431                 :             : 
    1432   [ +  +  +  +  :       11747 :     switch (var->promise)
          +  +  +  +  +  
                +  +  - ]
    1433                 :             :     {
    1434                 :        1231 :         case PLPGSQL_PROMISE_TG_NAME:
    1435         [ -  + ]:        1231 :             if (estate->trigdata == NULL)
    1436         [ #  # ]:           0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1437                 :        1231 :             assign_simple_var(estate, var,
    1438                 :        1231 :                               DirectFunctionCall1(namein,
    1439                 :             :                                                   CStringGetDatum(estate->trigdata->tg_trigger->tgname)),
    1440                 :             :                               false, true);
    1441                 :        1231 :             break;
    1442                 :             : 
    1443                 :        1859 :         case PLPGSQL_PROMISE_TG_WHEN:
    1444         [ -  + ]:        1859 :             if (estate->trigdata == NULL)
    1445         [ #  # ]:           0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1446         [ +  + ]:        1859 :             if (TRIGGER_FIRED_BEFORE(estate->trigdata->tg_event))
    1447                 :         778 :                 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                 :        1859 :             break;
    1455                 :             : 
    1456                 :        1743 :         case PLPGSQL_PROMISE_TG_LEVEL:
    1457         [ -  + ]:        1743 :             if (estate->trigdata == NULL)
    1458         [ #  # ]:           0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1459         [ +  + ]:        1743 :             if (TRIGGER_FIRED_FOR_ROW(estate->trigdata->tg_event))
    1460                 :        1075 :                 assign_text_var(estate, var, "ROW");
    1461         [ +  - ]:         668 :             else if (TRIGGER_FIRED_FOR_STATEMENT(estate->trigdata->tg_event))
    1462                 :         668 :                 assign_text_var(estate, var, "STATEMENT");
    1463                 :             :             else
    1464         [ #  # ]:           0 :                 elog(ERROR, "unrecognized trigger event type: not ROW or STATEMENT");
    1465                 :        1743 :             break;
    1466                 :             : 
    1467                 :        4267 :         case PLPGSQL_PROMISE_TG_OP:
    1468         [ -  + ]:        4267 :             if (estate->trigdata == NULL)
    1469         [ #  # ]:           0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1470         [ +  + ]:        4267 :             if (TRIGGER_FIRED_BY_INSERT(estate->trigdata->tg_event))
    1471                 :        2088 :                 assign_text_var(estate, var, "INSERT");
    1472         [ +  + ]:        2179 :             else if (TRIGGER_FIRED_BY_UPDATE(estate->trigdata->tg_event))
    1473                 :        1860 :                 assign_text_var(estate, var, "UPDATE");
    1474         [ +  + ]:         319 :             else if (TRIGGER_FIRED_BY_DELETE(estate->trigdata->tg_event))
    1475                 :         309 :                 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                 :        4267 :             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                 :        1432 :         case PLPGSQL_PROMISE_TG_ARGV:
    1517         [ -  + ]:        1432 :             if (estate->trigdata == NULL)
    1518         [ #  # ]:           0 :                 elog(ERROR, "trigger promise is not in a trigger function");
    1519         [ +  + ]:        1432 :             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                 :        1420 :                 int         nelems = estate->trigdata->tg_trigger->tgnargs;
    1526                 :             :                 Datum      *elems;
    1527                 :             :                 int         dims[1];
    1528                 :             :                 int         lbs[1];
    1529                 :             :                 int         i;
    1530                 :             : 
    1531                 :        1420 :                 elems = palloc_array(Datum, nelems);
    1532         [ +  + ]:        3164 :                 for (i = 0; i < nelems; i++)
    1533                 :        1744 :                     elems[i] = CStringGetTextDatum(estate->trigdata->tg_trigger->tgargs[i]);
    1534                 :        1420 :                 dims[0] = nelems;
    1535                 :        1420 :                 lbs[0] = 0;
    1536                 :             : 
    1537                 :        1420 :                 assign_simple_var(estate, var,
    1538                 :        1420 :                                   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                 :        1432 :             break;
    1549                 :             : 
    1550                 :         170 :         case PLPGSQL_PROMISE_TG_EVENT:
    1551         [ -  + ]:         170 :             if (estate->evtrigdata == NULL)
    1552         [ #  # ]:           0 :                 elog(ERROR, "event trigger promise is not in an event trigger function");
    1553                 :         170 :             assign_text_var(estate, var, estate->evtrigdata->event);
    1554                 :         170 :             break;
    1555                 :             : 
    1556                 :         210 :         case PLPGSQL_PROMISE_TG_TAG:
    1557         [ -  + ]:         210 :             if (estate->evtrigdata == NULL)
    1558         [ #  # ]:           0 :                 elog(ERROR, "event trigger promise is not in an event trigger function");
    1559                 :         210 :             assign_text_var(estate, var, GetCommandTagName(estate->evtrigdata->tag));
    1560                 :         210 :             break;
    1561                 :             : 
    1562                 :           0 :         default:
    1563         [ #  # ]:           0 :             elog(ERROR, "unrecognized promise type: %d", var->promise);
    1564                 :             :     }
    1565                 :             : 
    1566                 :       11747 :     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                 :       42859 : get_stmt_mcontext(PLpgSQL_execstate *estate)
    1576                 :             : {
    1577         [ +  + ]:       42859 :     if (estate->stmt_mcontext == NULL)
    1578                 :             :     {
    1579                 :       15539 :         estate->stmt_mcontext =
    1580                 :       15539 :             AllocSetContextCreate(estate->stmt_mcontext_parent,
    1581                 :             :                                   "PLpgSQL per-statement data",
    1582                 :             :                                   ALLOCSET_DEFAULT_SIZES);
    1583                 :             :     }
    1584                 :       42859 :     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                 :        3671 : pop_stmt_mcontext(PLpgSQL_execstate *estate)
    1614                 :             : {
    1615                 :             :     /* We need only pop the stack */
    1616                 :        3671 :     estate->stmt_mcontext = estate->stmt_mcontext_parent;
    1617                 :        3671 :     estate->stmt_mcontext_parent = MemoryContextGetParent(estate->stmt_mcontext);
    1618                 :        3671 : }
    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                 :        3600 : exception_matches_conditions(ErrorData *edata, PLpgSQL_condition *cond)
    1627                 :             : {
    1628         [ +  + ]:        4018 :     for (; cond != NULL; cond = cond->next)
    1629                 :             :     {
    1630                 :        4001 :         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         [ +  + ]:        4001 :         if (sqlerrstate == PLPGSQL_OTHERS)
    1638                 :             :         {
    1639         [ +  + ]:        3008 :             if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED &&
    1640         [ +  + ]:        3007 :                 edata->sqlerrcode != ERRCODE_ASSERT_FAILURE)
    1641                 :        3003 :                 return true;
    1642                 :             :         }
    1643                 :             :         /* Exact match? */
    1644         [ +  + ]:         993 :         else if (edata->sqlerrcode == sqlerrstate)
    1645                 :         578 :             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                 :       57532 : exec_toplevel_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
    1666                 :             : {
    1667                 :             :     int         rc;
    1668                 :             : 
    1669                 :       57532 :     estate->err_stmt = (PLpgSQL_stmt *) block;
    1670                 :             : 
    1671                 :             :     /* Let the plugin know that we are about to execute this statement */
    1672   [ -  +  -  - ]:       57532 :     if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
    1673                 :           0 :         ((*plpgsql_plugin_ptr)->stmt_beg) (estate, (PLpgSQL_stmt *) block);
    1674                 :             : 
    1675         [ -  + ]:       57532 :     CHECK_FOR_INTERRUPTS();
    1676                 :             : 
    1677                 :       57532 :     rc = exec_stmt_block(estate, block);
    1678                 :             : 
    1679                 :             :     /* Let the plugin know that we have finished executing this statement */
    1680   [ -  +  -  - ]:       56829 :     if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
    1681                 :           0 :         ((*plpgsql_plugin_ptr)->stmt_end) (estate, (PLpgSQL_stmt *) block);
    1682                 :             : 
    1683                 :       56829 :     estate->err_stmt = NULL;
    1684                 :             : 
    1685                 :       56829 :     return rc;
    1686                 :             : }
    1687                 :             : 
    1688                 :             : 
    1689                 :             : /* ----------
    1690                 :             :  * exec_stmt_block          Execute a block of statements
    1691                 :             :  * ----------
    1692                 :             :  */
    1693                 :             : static int
    1694                 :       66885 : exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
    1695                 :             : {
    1696                 :       66885 :     volatile int rc = -1;
    1697                 :             :     int         i;
    1698                 :             : 
    1699                 :             :     /*
    1700                 :             :      * First initialize all variables declared in this block
    1701                 :             :      */
    1702                 :       66885 :     estate->err_text = gettext_noop("during statement block local variable initialization");
    1703                 :             : 
    1704         [ +  + ]:       88954 :     for (i = 0; i < block->n_initvars; i++)
    1705                 :             :     {
    1706                 :       22103 :         int         n = block->initvarnos[i];
    1707                 :       22103 :         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                 :       22103 :         estate->err_var = (PLpgSQL_variable *) datum;
    1720                 :             : 
    1721      [ +  +  - ]:       22103 :         switch (datum->dtype)
    1722                 :             :         {
    1723                 :       18980 :             case PLPGSQL_DTYPE_VAR:
    1724                 :             :                 {
    1725                 :       18980 :                     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                 :       18980 :                     assign_simple_var(estate, var, (Datum) 0, true, false);
    1732                 :             : 
    1733         [ +  + ]:       18980 :                     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         [ +  + ]:       16570 :                         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                 :        2410 :                         exec_assign_expr(estate, (PLpgSQL_datum *) var,
    1755                 :             :                                          var->default_val);
    1756                 :             :                     }
    1757                 :             :                 }
    1758                 :       18955 :                 break;
    1759                 :             : 
    1760                 :        3123 :             case PLPGSQL_DTYPE_REC:
    1761                 :             :                 {
    1762                 :        3123 :                     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         [ +  + ]:        3123 :                     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                 :        3104 :                         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                 :        3114 :                 break;
    1788                 :             : 
    1789                 :           0 :             default:
    1790         [ #  # ]:           0 :                 elog(ERROR, "unrecognized dtype: %d", datum->dtype);
    1791                 :             :         }
    1792                 :             :     }
    1793                 :             : 
    1794                 :       66851 :     estate->err_var = NULL;
    1795                 :             : 
    1796         [ +  + ]:       66851 :     if (block->exceptions)
    1797                 :             :     {
    1798                 :             :         /*
    1799                 :             :          * Execute the statements in the block's body inside a sub-transaction
    1800                 :             :          */
    1801                 :        9499 :         MemoryContext oldcontext = CurrentMemoryContext;
    1802                 :        9499 :         ResourceOwner oldowner = CurrentResourceOwner;
    1803                 :        9499 :         ExprContext *old_eval_econtext = estate->eval_econtext;
    1804                 :        9499 :         ErrorData  *save_cur_error = estate->cur_error;
    1805                 :             :         MemoryContext stmt_mcontext;
    1806                 :             : 
    1807                 :        9499 :         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                 :        9499 :         stmt_mcontext = get_stmt_mcontext(estate);
    1819                 :             : 
    1820                 :        9499 :         BeginInternalSubTransaction(NULL);
    1821                 :             :         /* Want to run statements inside function's memory context */
    1822                 :        9499 :         MemoryContextSwitchTo(oldcontext);
    1823                 :             : 
    1824         [ +  + ]:        9499 :         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                 :        9499 :             plpgsql_create_econtext(estate);
    1833                 :             : 
    1834                 :        9499 :             estate->err_text = NULL;
    1835                 :             : 
    1836                 :             :             /* Run the block's statements */
    1837                 :        9499 :             rc = exec_stmts(estate, block->body);
    1838                 :             : 
    1839                 :        5908 :             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         [ +  + ]:        5908 :             if (rc == PLPGSQL_RC_RETURN &&
    1847         [ +  - ]:        1035 :                 !estate->retisset &&
    1848         [ +  - ]:        1035 :                 !estate->retisnull)
    1849                 :             :             {
    1850                 :             :                 int16       resTypLen;
    1851                 :             :                 bool        resTypByVal;
    1852                 :             : 
    1853                 :        1035 :                 get_typlenbyval(estate->rettype, &resTypLen, &resTypByVal);
    1854                 :        1035 :                 estate->retval = datumTransfer(estate->retval,
    1855                 :             :                                                resTypByVal, resTypLen);
    1856                 :             :             }
    1857                 :             : 
    1858                 :             :             /* Commit the inner transaction, return to outer xact context */
    1859                 :        5908 :             ReleaseCurrentSubTransaction();
    1860                 :        5908 :             MemoryContextSwitchTo(oldcontext);
    1861                 :        5908 :             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                 :        5908 :             estate->eval_econtext = old_eval_econtext;
    1871                 :             :         }
    1872                 :        3591 :         PG_CATCH();
    1873                 :             :         {
    1874                 :             :             ErrorData  *edata;
    1875                 :             :             ListCell   *e;
    1876                 :             : 
    1877                 :        3591 :             estate->err_text = gettext_noop("during exception cleanup");
    1878                 :             : 
    1879                 :             :             /* Save error info in our stmt_mcontext */
    1880                 :        3591 :             MemoryContextSwitchTo(stmt_mcontext);
    1881                 :        3591 :             edata = CopyErrorData();
    1882                 :        3591 :             FlushErrorState();
    1883                 :             : 
    1884                 :             :             /* Abort the inner transaction */
    1885                 :        3591 :             RollbackAndReleaseCurrentSubTransaction();
    1886                 :        3591 :             MemoryContextSwitchTo(oldcontext);
    1887                 :        3591 :             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                 :        3591 :             estate->stmt_mcontext_parent = stmt_mcontext;
    1896                 :        3591 :             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                 :        3591 :             MemoryContextDeleteChildren(stmt_mcontext);
    1908                 :             : 
    1909                 :             :             /* Revert to outer eval_econtext */
    1910                 :        3591 :             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                 :        3591 :             estate->eval_tuptable = NULL;
    1919                 :        3591 :             exec_eval_cleanup(estate);
    1920                 :             : 
    1921                 :             :             /* Look for a matching exception handler */
    1922   [ +  -  +  +  :        3608 :             foreach(e, block->exceptions->exc_list)
                   +  + ]
    1923                 :             :             {
    1924                 :        3600 :                 PLpgSQL_exception *exception = (PLpgSQL_exception *) lfirst(e);
    1925                 :             : 
    1926         [ +  + ]:        3600 :                 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                 :        3583 :                     state_var = (PLpgSQL_var *)
    1938                 :        3583 :                         estate->datums[block->exceptions->sqlstate_varno];
    1939                 :        3583 :                     errm_var = (PLpgSQL_var *)
    1940                 :        3583 :                         estate->datums[block->exceptions->sqlerrm_varno];
    1941                 :             : 
    1942                 :        3583 :                     assign_text_var(estate, state_var,
    1943                 :        3583 :                                     unpack_sql_state(edata->sqlerrcode));
    1944                 :        3583 :                     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                 :        3583 :                     estate->cur_error = edata;
    1951                 :             : 
    1952                 :        3583 :                     estate->err_text = NULL;
    1953                 :             : 
    1954                 :        3583 :                     rc = exec_stmts(estate, exception->action);
    1955                 :             : 
    1956                 :        3562 :                     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                 :        3570 :             estate->cur_error = save_cur_error;
    1966                 :             : 
    1967                 :             :             /* If no match found, re-throw the error */
    1968         [ +  + ]:        3570 :             if (e == NULL)
    1969                 :           8 :                 ReThrowError(edata);
    1970                 :             : 
    1971                 :             :             /* Restore stmt_mcontext stack and release the error data */
    1972                 :        3562 :             pop_stmt_mcontext(estate);
    1973                 :        3562 :             MemoryContextReset(stmt_mcontext);
    1974                 :             :         }
    1975         [ -  + ]:        9470 :         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                 :       57352 :         estate->err_text = NULL;
    1985                 :             : 
    1986                 :       57352 :         rc = exec_stmts(estate, block->body);
    1987                 :             :     }
    1988                 :             : 
    1989                 :       66141 :     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      [ +  +  - ]:       66141 :     switch (rc)
    1997                 :             :     {
    1998                 :       66129 :         case PLPGSQL_RC_OK:
    1999                 :             :         case PLPGSQL_RC_RETURN:
    2000                 :             :         case PLPGSQL_RC_CONTINUE:
    2001                 :       66129 :             return rc;
    2002                 :             : 
    2003                 :          12 :         case PLPGSQL_RC_EXIT:
    2004         [ +  + ]:          12 :             if (estate->exitlabel == NULL)
    2005                 :           6 :                 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                 :      212021 : exec_stmts(PLpgSQL_execstate *estate, List *stmts)
    2028                 :             : {
    2029                 :      212021 :     PLpgSQL_stmt *save_estmt = estate->err_stmt;
    2030                 :             :     ListCell   *s;
    2031                 :             : 
    2032         [ +  + ]:      212021 :     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         [ +  + ]:       54923 :         CHECK_FOR_INTERRUPTS();
    2040                 :       54923 :         return PLPGSQL_RC_OK;
    2041                 :             :     }
    2042                 :             : 
    2043   [ +  -  +  +  :      391006 :     foreach(s, stmts)
                   +  + ]
    2044                 :             :     {
    2045                 :      304339 :         PLpgSQL_stmt *stmt = (PLpgSQL_stmt *) lfirst(s);
    2046                 :             :         int         rc;
    2047                 :             : 
    2048                 :      304339 :         estate->err_stmt = stmt;
    2049                 :             : 
    2050                 :             :         /* Let the plugin know that we are about to execute this statement */
    2051   [ -  +  -  - ]:      304339 :         if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
    2052                 :           0 :             ((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
    2053                 :             : 
    2054         [ -  + ]:      304339 :         CHECK_FOR_INTERRUPTS();
    2055                 :             : 
    2056   [ +  +  +  +  :      304339 :         switch (stmt->cmd_type)
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  - ]
    2057                 :             :         {
    2058                 :        9353 :             case PLPGSQL_STMT_BLOCK:
    2059                 :        9353 :                 rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);
    2060                 :        9312 :                 break;
    2061                 :             : 
    2062                 :       64027 :             case PLPGSQL_STMT_ASSIGN:
    2063                 :       64027 :                 rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
    2064                 :       63875 :                 break;
    2065                 :             : 
    2066                 :        3930 :             case PLPGSQL_STMT_PERFORM:
    2067                 :        3930 :                 rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
    2068                 :        2936 :                 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                 :       76156 :             case PLPGSQL_STMT_IF:
    2079                 :       76156 :                 rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
    2080                 :       76027 :                 break;
    2081                 :             : 
    2082                 :         144 :             case PLPGSQL_STMT_CASE:
    2083                 :         144 :                 rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
    2084                 :         141 :                 break;
    2085                 :             : 
    2086                 :          59 :             case PLPGSQL_STMT_LOOP:
    2087                 :          59 :                 rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
    2088                 :          59 :                 break;
    2089                 :             : 
    2090                 :         286 :             case PLPGSQL_STMT_WHILE:
    2091                 :         286 :                 rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);
    2092                 :         286 :                 break;
    2093                 :             : 
    2094                 :        3057 :             case PLPGSQL_STMT_FORI:
    2095                 :        3057 :                 rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
    2096                 :        3042 :                 break;
    2097                 :             : 
    2098                 :        1642 :             case PLPGSQL_STMT_FORS:
    2099                 :        1642 :                 rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);
    2100                 :        1614 :                 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                 :        2100 :             case PLPGSQL_STMT_EXIT:
    2111                 :        2100 :                 rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
    2112                 :        2100 :                 break;
    2113                 :             : 
    2114                 :       56889 :             case PLPGSQL_STMT_RETURN:
    2115                 :       56889 :                 rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
    2116                 :       56825 :                 break;
    2117                 :             : 
    2118                 :        3921 :             case PLPGSQL_STMT_RETURN_NEXT:
    2119                 :        3921 :                 rc = exec_stmt_return_next(estate, (PLpgSQL_stmt_return_next *) stmt);
    2120                 :        3919 :                 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                 :       13557 :             case PLPGSQL_STMT_RAISE:
    2127                 :       13557 :                 rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
    2128                 :       12907 :                 break;
    2129                 :             : 
    2130                 :        4476 :             case PLPGSQL_STMT_ASSERT:
    2131                 :        4476 :                 rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
    2132                 :        4460 :                 break;
    2133                 :             : 
    2134                 :       42512 :             case PLPGSQL_STMT_EXECSQL:
    2135                 :       42512 :                 rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
    2136                 :       40394 :                 break;
    2137                 :             : 
    2138                 :       11148 :             case PLPGSQL_STMT_DYNEXECUTE:
    2139                 :       11148 :                 rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt);
    2140                 :       10970 :                 break;
    2141                 :             : 
    2142                 :        6390 :             case PLPGSQL_STMT_DYNFORS:
    2143                 :        6390 :                 rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
    2144                 :        6386 :                 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                 :          56 :             case PLPGSQL_STMT_ROLLBACK:
    2163                 :          56 :                 rc = exec_stmt_rollback(estate, (PLpgSQL_stmt_rollback *) stmt);
    2164                 :          53 :                 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   [ -  +  -  - ]:      299887 :         if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
    2175                 :           0 :             ((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
    2176                 :             : 
    2177         [ +  + ]:      299887 :         if (rc != PLPGSQL_RC_OK)
    2178                 :             :         {
    2179                 :       65979 :             estate->err_stmt = save_estmt;
    2180                 :       65979 :             return rc;
    2181                 :             :         }
    2182                 :             :     }                           /* end of loop over statements */
    2183                 :             : 
    2184                 :       86667 :     estate->err_stmt = save_estmt;
    2185                 :       86667 :     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                 :       64027 : exec_stmt_assign(PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt)
    2196                 :             : {
    2197                 :             :     Assert(stmt->varno >= 0);
    2198                 :             : 
    2199                 :       64027 :     exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
    2200                 :             : 
    2201                 :       63875 :     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                 :        3930 : exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
    2212                 :             : {
    2213                 :        3930 :     PLpgSQL_expr *expr = stmt->expr;
    2214                 :             : 
    2215                 :        3930 :     (void) exec_run_select(estate, expr, 0, NULL);
    2216                 :        2936 :     exec_set_found(estate, (estate->eval_processed != 0));
    2217                 :        2936 :     exec_eval_cleanup(estate);
    2218                 :             : 
    2219                 :        2936 :     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                 :       76156 : exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
    2558                 :             : {
    2559                 :             :     bool        value;
    2560                 :             :     bool        isnull;
    2561                 :             :     ListCell   *lc;
    2562                 :             : 
    2563                 :       76156 :     value = exec_eval_boolean(estate, stmt->cond, &isnull);
    2564                 :       76156 :     exec_eval_cleanup(estate);
    2565   [ +  +  +  + ]:       76156 :     if (!isnull && value)
    2566                 :       14900 :         return exec_stmts(estate, stmt->then_body);
    2567                 :             : 
    2568   [ +  +  +  +  :       61446 :     foreach(lc, stmt->elsif_list)
                   +  + ]
    2569                 :             :     {
    2570                 :         698 :         PLpgSQL_if_elsif *elif = (PLpgSQL_if_elsif *) lfirst(lc);
    2571                 :             : 
    2572                 :         698 :         value = exec_eval_boolean(estate, elif->cond, &isnull);
    2573                 :         698 :         exec_eval_cleanup(estate);
    2574   [ +  -  +  + ]:         698 :         if (!isnull && value)
    2575                 :         508 :             return exec_stmts(estate, elif->stmts);
    2576                 :             :     }
    2577                 :             : 
    2578                 :       60748 :     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                 :          59 : exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
    2675                 :             : {
    2676                 :          59 :     int         rc = PLPGSQL_RC_OK;
    2677                 :             : 
    2678                 :             :     for (;;)
    2679                 :             :     {
    2680                 :        4799 :         rc = exec_stmts(estate, stmt->body);
    2681                 :             : 
    2682   [ -  +  +  +  :        4799 :         LOOP_RC_PROCESSING(stmt->label, break);
          +  +  +  +  +  
          -  +  +  +  +  
             +  +  +  - ]
    2683                 :             :     }
    2684                 :             : 
    2685                 :          59 :     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                 :         286 : exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
    2697                 :             : {
    2698                 :         286 :     int         rc = PLPGSQL_RC_OK;
    2699                 :             : 
    2700                 :             :     for (;;)
    2701                 :        2099 :     {
    2702                 :             :         bool        value;
    2703                 :             :         bool        isnull;
    2704                 :             : 
    2705                 :        2385 :         value = exec_eval_boolean(estate, stmt->cond, &isnull);
    2706                 :        2385 :         exec_eval_cleanup(estate);
    2707                 :             : 
    2708   [ +  -  +  + ]:        2385 :         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                 :         286 :     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                 :        3057 : 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                 :        3057 :     bool        found = false;
    2738                 :        3057 :     int         rc = PLPGSQL_RC_OK;
    2739                 :             : 
    2740                 :        3057 :     var = (PLpgSQL_var *) (estate->datums[stmt->var->dno]);
    2741                 :             : 
    2742                 :             :     /*
    2743                 :             :      * Get the value of the lower bound
    2744                 :             :      */
    2745                 :        3057 :     value = exec_eval_expr(estate, stmt->lower,
    2746                 :             :                            &isnull, &valtype, &valtypmod);
    2747                 :        3057 :     value = exec_cast_value(estate, value, &isnull,
    2748                 :             :                             valtype, valtypmod,
    2749                 :        3057 :                             var->datatype->typoid,
    2750                 :        3057 :                             var->datatype->atttypmod);
    2751         [ -  + ]:        3057 :     if (isnull)
    2752         [ #  # ]:           0 :         ereport(ERROR,
    2753                 :             :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    2754                 :             :                  errmsg("lower bound of FOR loop cannot be null")));
    2755                 :        3057 :     loop_value = DatumGetInt32(value);
    2756                 :        3057 :     exec_eval_cleanup(estate);
    2757                 :             : 
    2758                 :             :     /*
    2759                 :             :      * Get the value of the upper bound
    2760                 :             :      */
    2761                 :        3057 :     value = exec_eval_expr(estate, stmt->upper,
    2762                 :             :                            &isnull, &valtype, &valtypmod);
    2763                 :        3057 :     value = exec_cast_value(estate, value, &isnull,
    2764                 :             :                             valtype, valtypmod,
    2765                 :        3057 :                             var->datatype->typoid,
    2766                 :        3057 :                             var->datatype->atttypmod);
    2767         [ -  + ]:        3057 :     if (isnull)
    2768         [ #  # ]:           0 :         ereport(ERROR,
    2769                 :             :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
    2770                 :             :                  errmsg("upper bound of FOR loop cannot be null")));
    2771                 :        3057 :     end_value = DatumGetInt32(value);
    2772                 :        3057 :     exec_eval_cleanup(estate);
    2773                 :             : 
    2774                 :             :     /*
    2775                 :             :      * Get the step value
    2776                 :             :      */
    2777         [ +  + ]:        3057 :     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                 :        3048 :         step_value = 1;
    2798                 :             : 
    2799                 :             :     /*
    2800                 :             :      * Now do the loop
    2801                 :             :      */
    2802                 :             :     for (;;)
    2803                 :             :     {
    2804                 :             :         /*
    2805                 :             :          * Check against upper bound
    2806                 :             :          */
    2807         [ +  + ]:       22056 :         if (stmt->reverse)
    2808                 :             :         {
    2809         [ +  + ]:           8 :             if (loop_value < end_value)
    2810                 :           1 :                 break;
    2811                 :             :         }
    2812                 :             :         else
    2813                 :             :         {
    2814         [ +  + ]:       22048 :             if (loop_value > end_value)
    2815                 :        3028 :                 break;
    2816                 :             :         }
    2817                 :             : 
    2818                 :       19027 :         found = true;           /* looped at least once */
    2819                 :             : 
    2820                 :             :         /*
    2821                 :             :          * Assign current value to loop var
    2822                 :             :          */
    2823                 :       19027 :         assign_simple_var(estate, var, Int32GetDatum(loop_value), false, false);
    2824                 :             : 
    2825                 :             :         /*
    2826                 :             :          * Execute the statements
    2827                 :             :          */
    2828                 :       19027 :         rc = exec_stmts(estate, stmt->body);
    2829                 :             : 
    2830   [ +  +  +  +  :       19015 :         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         [ +  + ]:       19004 :         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         [ +  + ]:       18997 :             if (loop_value > (PG_INT32_MAX - step_value))
    2845                 :           1 :                 break;
    2846                 :       18996 :             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                 :        3042 :     exec_set_found(estate, found);
    2857                 :             : 
    2858                 :        3042 :     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                 :        1642 : 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                 :        1642 :     exec_run_select(estate, stmt->query, 0, &portal);
    2879                 :             : 
    2880                 :             :     /*
    2881                 :             :      * Execute the loop
    2882                 :             :      */
    2883                 :        1634 :     rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, true);
    2884                 :             : 
    2885                 :             :     /*
    2886                 :             :      * Close the implicit cursor
    2887                 :             :      */
    2888                 :        1614 :     SPI_cursor_close(portal);
    2889                 :             : 
    2890                 :        1614 :     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                 :        2100 : exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
    3196                 :             : {
    3197                 :             :     /*
    3198                 :             :      * If the exit / continue has a condition, evaluate it
    3199                 :             :      */
    3200         [ +  + ]:        2100 :     if (stmt->cond != NULL)
    3201                 :             :     {
    3202                 :             :         bool        value;
    3203                 :             :         bool        isnull;
    3204                 :             : 
    3205                 :        1695 :         value = exec_eval_boolean(estate, stmt->cond, &isnull);
    3206                 :        1695 :         exec_eval_cleanup(estate);
    3207   [ +  -  +  + ]:        1695 :         if (isnull || value == false)
    3208                 :        1597 :             return PLPGSQL_RC_OK;
    3209                 :             :     }
    3210                 :             : 
    3211                 :         503 :     estate->exitlabel = stmt->label;
    3212         [ +  + ]:         503 :     if (stmt->is_exit)
    3213                 :          61 :         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                 :       56889 : 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         [ +  + ]:       56889 :     if (estate->retisset)
    3236                 :        2460 :         return PLPGSQL_RC_RETURN;
    3237                 :             : 
    3238                 :             :     /* initialize for null result */
    3239                 :       54429 :     estate->retval = (Datum) 0;
    3240                 :       54429 :     estate->retisnull = true;
    3241                 :       54429 :     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         [ +  + ]:       54429 :     if (stmt->retvarno >= 0)
    3256                 :             :     {
    3257                 :       36143 :         PLpgSQL_datum *retvar = estate->datums[stmt->retvarno];
    3258                 :             : 
    3259   [ -  +  +  - ]:       36143 :         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                 :       24171 :             case PLPGSQL_DTYPE_VAR:
    3268                 :             :                 {
    3269                 :       24171 :                     PLpgSQL_var *var = (PLpgSQL_var *) retvar;
    3270                 :             : 
    3271                 :       24171 :                     estate->retval = var->value;
    3272                 :       24171 :                     estate->retisnull = var->isnull;
    3273                 :       24171 :                     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   [ +  +  +  - ]:       24171 :                     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                 :       24167 :                 break;
    3289                 :             : 
    3290                 :       11972 :             case PLPGSQL_DTYPE_ROW:
    3291                 :             :             case PLPGSQL_DTYPE_REC:
    3292                 :             :                 {
    3293                 :             :                     /* exec_eval_datum can handle these cases */
    3294                 :             :                     int32       rettypmod;
    3295                 :             : 
    3296                 :       11972 :                     exec_eval_datum(estate,
    3297                 :             :                                     retvar,
    3298                 :             :                                     &estate->rettype,
    3299                 :             :                                     &rettypmod,
    3300                 :             :                                     &estate->retval,
    3301                 :             :                                     &estate->retisnull);
    3302                 :             :                 }
    3303                 :       11972 :                 break;
    3304                 :             : 
    3305                 :           0 :             default:
    3306         [ #  # ]:           0 :                 elog(ERROR, "unrecognized dtype: %d", retvar->dtype);
    3307                 :             :         }
    3308                 :             : 
    3309                 :       36139 :         return PLPGSQL_RC_RETURN;
    3310                 :             :     }
    3311                 :             : 
    3312         [ +  + ]:       18286 :     if (stmt->expr != NULL)
    3313                 :             :     {
    3314                 :             :         int32       rettypmod;
    3315                 :             : 
    3316                 :       14937 :         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   [ +  +  +  + ]:       14881 :         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                 :       14877 :         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         [ +  - ]:        3349 :     if (estate->fn_rettype == VOIDOID &&
    3340         [ +  + ]:        3349 :         estate->func->fn_prokind != PROKIND_PROCEDURE)
    3341                 :             :     {
    3342                 :        3293 :         estate->retval = (Datum) 0;
    3343                 :        3293 :         estate->retisnull = false;
    3344                 :        3293 :         estate->rettype = VOIDOID;
    3345                 :             :     }
    3346                 :             : 
    3347                 :        3349 :     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                 :        3921 : 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         [ -  + ]:        3921 :     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         [ +  + ]:        3921 :     if (estate->tuple_store == NULL)
    3371                 :         669 :         exec_init_tuple_store(estate);
    3372                 :             : 
    3373                 :             :     /* tuple_store_desc will be filled by exec_init_tuple_store */
    3374                 :        3921 :     tupdesc = estate->tuple_store_desc;
    3375                 :        3921 :     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         [ +  + ]:        3921 :     if (stmt->retvarno >= 0)
    3388                 :             :     {
    3389                 :        3558 :         PLpgSQL_datum *retvar = estate->datums[stmt->retvarno];
    3390                 :             : 
    3391   [ -  +  +  +  :        3558 :         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                 :        3326 :             case PLPGSQL_DTYPE_VAR:
    3400                 :             :                 {
    3401                 :        3326 :                     PLpgSQL_var *var = (PLpgSQL_var *) retvar;
    3402                 :        3326 :                     Datum       retval = var->value;
    3403                 :        3326 :                     bool        isNull = var->isnull;
    3404                 :             :                     Form_pg_attribute attr;
    3405                 :             : 
    3406         [ -  + ]:        3326 :                     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   [ +  -  +  + ]:        3326 :                     retval = MakeExpandedObjectReadOnly(retval,
    3413                 :             :                                                         isNull,
    3414                 :             :                                                         var->datatype->typlen);
    3415                 :             : 
    3416                 :             :                     /* coerce type if needed */
    3417                 :        3326 :                     attr = TupleDescAttr(tupdesc, 0);
    3418                 :        6652 :                     retval = exec_cast_value(estate,
    3419                 :             :                                              retval,
    3420                 :             :                                              &isNull,
    3421                 :        3326 :                                              var->datatype->typoid,
    3422                 :        3326 :                                              var->datatype->atttypmod,
    3423                 :             :                                              attr->atttypid,
    3424                 :             :                                              attr->atttypmod);
    3425                 :             : 
    3426                 :        3326 :                     tuplestore_putvalues(estate->tuple_store, tupdesc,
    3427                 :             :                                          &retval, &isNull);
    3428                 :             :                 }
    3429                 :        3326 :                 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                 :        3919 :     exec_eval_cleanup(estate);
    3566                 :             : 
    3567                 :        3919 :     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                 :        2459 : exec_init_tuple_store(PLpgSQL_execstate *estate)
    3703                 :             : {
    3704                 :        2459 :     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   [ +  -  -  + ]:        2459 :     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         [ +  - ]:        2459 :     if (!(rsi->allowedModes & SFRM_Materialize) ||
    3717         [ -  + ]:        2459 :         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                 :        2459 :     oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
    3730                 :        2459 :     oldowner = CurrentResourceOwner;
    3731                 :        2459 :     CurrentResourceOwner = estate->tuple_store_owner;
    3732                 :             : 
    3733                 :        2459 :     estate->tuple_store =
    3734                 :        2459 :         tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
    3735                 :             :                               false, work_mem);
    3736                 :             : 
    3737                 :        2459 :     CurrentResourceOwner = oldowner;
    3738                 :        2459 :     MemoryContextSwitchTo(oldcxt);
    3739                 :             : 
    3740                 :        2459 :     estate->tuple_store_desc = rsi->expectedDesc;
    3741                 :        2459 : }
    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                 :       13557 : exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
    3759                 :             : {
    3760                 :       13557 :     int         err_code = 0;
    3761                 :       13557 :     char       *condname = NULL;
    3762                 :       13557 :     char       *err_message = NULL;
    3763                 :       13557 :     char       *err_detail = NULL;
    3764                 :       13557 :     char       *err_hint = NULL;
    3765                 :       13557 :     char       *err_column = NULL;
    3766                 :       13557 :     char       *err_constraint = NULL;
    3767                 :       13557 :     char       *err_datatype = NULL;
    3768                 :       13557 :     char       *err_table = NULL;
    3769                 :       13557 :     char       *err_schema = NULL;
    3770                 :             :     MemoryContext stmt_mcontext;
    3771                 :             :     ListCell   *lc;
    3772                 :             : 
    3773                 :             :     /* RAISE with no parameters: re-throw current exception */
    3774   [ +  +  +  + ]:       13557 :     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                 :       13533 :     stmt_mcontext = get_stmt_mcontext(estate);
    3787                 :             : 
    3788         [ +  + ]:       13533 :     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         [ +  + ]:       13533 :     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                 :       13083 :         oldcontext = MemoryContextSwitchTo(stmt_mcontext);
    3803                 :       13083 :         initStringInfo(&ds);
    3804                 :       13083 :         MemoryContextSwitchTo(oldcontext);
    3805                 :             : 
    3806                 :       13083 :         current_param = list_head(stmt->params);
    3807                 :             : 
    3808         [ +  + ]:      223219 :         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         [ +  + ]:      210153 :             if (cp[0] == '%')
    3815                 :             :             {
    3816                 :             :                 Oid         paramtypeid;
    3817                 :             :                 int32       paramtypmod;
    3818                 :             :                 Datum       paramvalue;
    3819                 :             :                 bool        paramisnull;
    3820                 :             :                 char       *extval;
    3821                 :             : 
    3822         [ +  + ]:       31706 :                 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         [ -  + ]:       31702 :                 if (current_param == NULL)
    3831         [ #  # ]:           0 :                     elog(ERROR, "unexpected RAISE parameter list length");
    3832                 :             : 
    3833                 :       31702 :                 paramvalue = exec_eval_expr(estate,
    3834                 :       31702 :                                             (PLpgSQL_expr *) lfirst(current_param),
    3835                 :             :                                             &paramisnull,
    3836                 :             :                                             &paramtypeid,
    3837                 :             :                                             &paramtypmod);
    3838                 :             : 
    3839         [ +  + ]:       31685 :                 if (paramisnull)
    3840                 :         548 :                     extval = "<NULL>";
    3841                 :             :                 else
    3842                 :       31137 :                     extval = convert_value_to_string(estate,
    3843                 :             :                                                      paramvalue,
    3844                 :             :                                                      paramtypeid);
    3845                 :       31685 :                 appendStringInfoString(&ds, extval);
    3846                 :       31685 :                 current_param = lnext(stmt->params, current_param);
    3847                 :       31685 :                 exec_eval_cleanup(estate);
    3848                 :             :             }
    3849                 :             :             else
    3850                 :      178447 :                 appendStringInfoChar(&ds, cp[0]);
    3851                 :             :         }
    3852                 :             : 
    3853                 :             :         /* should have been checked at compile time */
    3854         [ -  + ]:       13066 :         if (current_param != NULL)
    3855         [ #  # ]:           0 :             elog(ERROR, "unexpected RAISE parameter list length");
    3856                 :             : 
    3857                 :       13066 :         err_message = ds.data;
    3858                 :             :     }
    3859                 :             : 
    3860   [ +  +  +  +  :       14026 :     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   [ +  +  +  + ]:       13508 :     if (err_code == 0 && stmt->elog_level >= ERROR)
    3924                 :         147 :         err_code = ERRCODE_RAISE_EXCEPTION;
    3925                 :             : 
    3926                 :             :     /* Default error message if nothing specified */
    3927         [ +  + ]:       13508 :     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   [ +  +  +  +  :       13508 :     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                 :       12907 :     MemoryContextReset(stmt_mcontext);
    3960                 :             : 
    3961                 :       12907 :     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                 :       57532 : 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                 :       57532 :     func->cur_estate = estate;
    4022                 :             : 
    4023                 :       57532 :     estate->func = func;
    4024                 :       57532 :     estate->trigdata = NULL;
    4025                 :       57532 :     estate->evtrigdata = NULL;
    4026                 :             : 
    4027                 :       57532 :     estate->retval = (Datum) 0;
    4028                 :       57532 :     estate->retisnull = true;
    4029                 :       57532 :     estate->rettype = InvalidOid;
    4030                 :             : 
    4031                 :       57532 :     estate->fn_rettype = func->fn_rettype;
    4032                 :       57532 :     estate->retistuple = func->fn_retistuple;
    4033                 :       57532 :     estate->retisset = func->fn_retset;
    4034                 :             : 
    4035                 :       57532 :     estate->readonly_func = func->fn_readonly;
    4036                 :       57532 :     estate->atomic = true;
    4037                 :             : 
    4038                 :       57532 :     estate->exitlabel = NULL;
    4039                 :       57532 :     estate->cur_error = NULL;
    4040                 :             : 
    4041                 :       57532 :     estate->tuple_store = NULL;
    4042                 :       57532 :     estate->tuple_store_desc = NULL;
    4043         [ +  + ]:       57532 :     if (rsi)
    4044                 :             :     {
    4045                 :        2674 :         estate->tuple_store_cxt = rsi->econtext->ecxt_per_query_memory;
    4046                 :        2674 :         estate->tuple_store_owner = CurrentResourceOwner;
    4047                 :             :     }
    4048                 :             :     else
    4049                 :             :     {
    4050                 :       54858 :         estate->tuple_store_cxt = NULL;
    4051                 :       54858 :         estate->tuple_store_owner = NULL;
    4052                 :             :     }
    4053                 :       57532 :     estate->rsi = rsi;
    4054                 :             : 
    4055                 :       57532 :     estate->found_varno = func->found_varno;
    4056                 :       57532 :     estate->ndatums = func->ndatums;
    4057                 :       57532 :     estate->datums = NULL;
    4058                 :             :     /* the datums array will be filled by copy_plpgsql_datums() */
    4059                 :       57532 :     estate->datum_context = CurrentMemoryContext;
    4060                 :             : 
    4061                 :             :     /* initialize our ParamListInfo with appropriate hook functions */
    4062                 :       57532 :     estate->paramLI = makeParamList(0);
    4063                 :       57532 :     estate->paramLI->paramFetch = plpgsql_param_fetch;
    4064                 :       57532 :     estate->paramLI->paramFetchArg = estate;
    4065                 :       57532 :     estate->paramLI->paramCompile = plpgsql_param_compile;
    4066                 :       57532 :     estate->paramLI->paramCompileArg = NULL;  /* not needed */
    4067                 :       57532 :     estate->paramLI->parserSetup = (ParserSetupHook) plpgsql_parser_setup;
    4068                 :       57532 :     estate->paramLI->parserSetupArg = NULL; /* filled during use */
    4069                 :       57532 :     estate->paramLI->numParams = estate->ndatums;
    4070                 :             : 
    4071                 :             :     /* Create the session-wide cast-expression hash if we didn't already */
    4072         [ +  + ]:       57532 :     if (cast_expr_hash == NULL)
    4073                 :             :     {
    4074                 :         712 :         ctl.keysize = sizeof(plpgsql_CastHashKey);
    4075                 :         712 :         ctl.entrysize = sizeof(plpgsql_CastExprHashEntry);
    4076                 :         712 :         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         [ +  + ]:       57532 :     if (simple_eval_estate)
    4084                 :             :     {
    4085                 :         829 :         estate->simple_eval_estate = simple_eval_estate;
    4086                 :             :         /* Private cast hash just lives in function's main context */
    4087                 :         829 :         ctl.keysize = sizeof(plpgsql_CastHashKey);
    4088                 :         829 :         ctl.entrysize = sizeof(plpgsql_CastHashEntry);
    4089                 :         829 :         ctl.hcxt = CurrentMemoryContext;
    4090                 :         829 :         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                 :       56703 :         estate->simple_eval_estate = shared_simple_eval_estate;
    4098                 :             :         /* Create the session-wide cast-info hash table if we didn't already */
    4099         [ +  + ]:       56703 :         if (shared_cast_hash == NULL)
    4100                 :             :         {
    4101                 :         596 :             ctl.keysize = sizeof(plpgsql_CastHashKey);
    4102                 :         596 :             ctl.entrysize = sizeof(plpgsql_CastHashEntry);
    4103                 :         596 :             shared_cast_hash = hash_create("PLpgSQL cast cache",
    4104                 :             :                                            16,  /* start small and extend */
    4105                 :             :                                            &ctl,
    4106                 :             :                                            HASH_ELEM | HASH_BLOBS);
    4107                 :             :         }
    4108                 :       56703 :         estate->cast_hash = shared_cast_hash;
    4109                 :             :     }
    4110                 :             :     /* likewise for the simple-expression resource owner */
    4111         [ +  + ]:       57532 :     if (simple_eval_resowner)
    4112                 :         829 :         estate->simple_eval_resowner = simple_eval_resowner;
    4113                 :             :     else
    4114                 :       56703 :         estate->simple_eval_resowner = shared_simple_eval_resowner;
    4115                 :             : 
    4116                 :             :     /* if there's a procedure resowner, it'll be filled in later */
    4117                 :       57532 :     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                 :       57532 :     estate->stmt_mcontext = NULL;
    4125                 :       57532 :     estate->stmt_mcontext_parent = CurrentMemoryContext;
    4126                 :             : 
    4127                 :       57532 :     estate->eval_tuptable = NULL;
    4128                 :       57532 :     estate->eval_processed = 0;
    4129                 :       57532 :     estate->eval_econtext = NULL;
    4130                 :             : 
    4131                 :       57532 :     estate->err_stmt = NULL;
    4132                 :       57532 :     estate->err_var = NULL;
    4133                 :       57532 :     estate->err_text = NULL;
    4134                 :             : 
    4135                 :       57532 :     estate->plugin_info = NULL;
    4136                 :             : 
    4137                 :             :     /*
    4138                 :             :      * Create an EState and ExprContext for evaluation of simple expressions.
    4139                 :             :      */
    4140                 :       57532 :     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         [ -  + ]:       57532 :     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                 :       57532 : }
    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                 :      331327 : exec_eval_cleanup(PLpgSQL_execstate *estate)
    4170                 :             : {
    4171                 :             :     /* Clear result of a full SPI_execute */
    4172         [ +  + ]:      331327 :     if (estate->eval_tuptable != NULL)
    4173                 :        8208 :         SPI_freetuptable(estate->eval_tuptable);
    4174                 :      331327 :     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         [ +  + ]:      331327 :     if (estate->eval_econtext != NULL)
    4181                 :      274545 :         ResetExprContext(estate->eval_econtext);
    4182                 :      331327 : }
    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                 :       18166 : 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                 :       18166 :     memset(&options, 0, sizeof(options));
    4216                 :       18166 :     options.parserSetup = (ParserSetupHook) plpgsql_parser_setup;
    4217                 :       18166 :     options.parserSetupArg = expr;
    4218                 :       18166 :     options.parseMode = expr->parseMode;
    4219                 :       18166 :     options.cursorOptions = cursorOptions;
    4220                 :       18166 :     plan = SPI_prepare_extended(expr->query, &options);
    4221         [ -  + ]:       18105 :     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                 :       18105 :     SPI_keepplan(plan);
    4226                 :       18105 :     expr->plan = plan;
    4227                 :             : 
    4228                 :             :     /* Check to see if it's a simple expression */
    4229                 :       18105 :     exec_simple_check_plan(estate, expr);
    4230                 :       18076 : }
    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                 :       42552 : exec_stmt_execsql(PLpgSQL_execstate *estate,
    4242                 :             :                   PLpgSQL_stmt_execsql *stmt)
    4243                 :             : {
    4244                 :             :     ParamListInfo paramLI;
    4245                 :             :     long        tcount;
    4246                 :             :     int         rc;
    4247                 :       42552 :     PLpgSQL_expr *expr = stmt->sqlstmt;
    4248                 :       42552 :     int         too_many_rows_level = 0;
    4249                 :             : 
    4250         [ +  + ]:       42552 :     if (plpgsql_extra_errors & PLPGSQL_XCHECK_TOOMANYROWS)
    4251                 :           4 :         too_many_rows_level = ERROR;
    4252         [ +  + ]:       42548 :     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         [ +  + ]:       42552 :     if (expr->plan == NULL)
    4260                 :        1711 :         exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK);
    4261                 :             : 
    4262         [ +  + ]:       42538 :     if (!stmt->mod_stmt_set)
    4263                 :             :     {
    4264                 :             :         ListCell   *l;
    4265                 :             : 
    4266                 :        1707 :         stmt->mod_stmt = false;
    4267   [ +  -  +  +  :        2862 :         foreach(l, SPI_plan_get_plan_sources(expr->plan))
                   +  + ]
    4268                 :             :         {
    4269                 :        1707 :             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         [ +  + ]:        1707 :             if (plansource->commandTag == CMDTAG_INSERT ||
    4279         [ +  + ]:        1387 :                 plansource->commandTag == CMDTAG_UPDATE ||
    4280         [ +  + ]:        1249 :                 plansource->commandTag == CMDTAG_DELETE ||
    4281         [ +  + ]:        1191 :                 plansource->commandTag == CMDTAG_MERGE)
    4282                 :             :             {
    4283                 :         552 :                 stmt->mod_stmt = true;
    4284                 :         552 :                 break;
    4285                 :             :             }
    4286                 :             :         }
    4287                 :        1707 :         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   [ +  +  +  + ]:       42538 :     if (expr->expr_simple_expr && stmt->into)
    4301                 :             :     {
    4302                 :        2927 :         PLpgSQL_datum *target = estate->datums[stmt->target->dno];
    4303                 :             : 
    4304         [ +  + ]:        2927 :         if (target->dtype == PLPGSQL_DTYPE_ROW)
    4305                 :             :         {
    4306                 :        2922 :             PLpgSQL_row *row = (PLpgSQL_row *) target;
    4307                 :             : 
    4308         [ +  + ]:        2922 :             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                 :        2914 :                 plerrcontext.callback = plpgsql_execsql_error_callback;
    4322                 :        2914 :                 plerrcontext.arg = expr;
    4323                 :        2914 :                 plerrcontext.previous = error_context_stack;
    4324                 :        2914 :                 error_context_stack = &plerrcontext;
    4325                 :             : 
    4326                 :             :                 /* If first time through, create a plan for this expression */
    4327         [ -  + ]:        2914 :                 if (expr->plan == NULL)
    4328                 :           0 :                     exec_prepare_plan(estate, expr, 0);
    4329                 :             : 
    4330                 :             :                 /* And evaluate the expression */
    4331                 :        2914 :                 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                 :        2908 :                 error_context_stack = plerrcontext.previous;
    4339                 :             : 
    4340                 :             :                 /* Assign the result to the INTO target */
    4341                 :        2908 :                 exec_assign_value(estate, estate->datums[row->varnos[0]],
    4342                 :             :                                   value, isnull, valtype, valtypmod);
    4343                 :        2907 :                 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                 :        2907 :                 exec_set_found(estate, true);
    4351                 :        2907 :                 estate->eval_processed = 1;
    4352                 :             : 
    4353                 :        2907 :                 return PLPGSQL_RC_OK;
    4354                 :             :             }
    4355                 :             :         }
    4356                 :             :     }
    4357                 :             : 
    4358                 :             :     /*
    4359                 :             :      * Set up ParamListInfo to pass to executor
    4360                 :             :      */
    4361                 :       39624 :     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         [ +  + ]:       39624 :     if (stmt->into)
    4376                 :             :     {
    4377   [ +  +  +  +  :        8529 :         if (stmt->strict || stmt->mod_stmt || too_many_rows_level)
                   +  + ]
    4378                 :        1132 :             tcount = 2;
    4379                 :             :         else
    4380                 :        7397 :             tcount = 1;
    4381                 :             :     }
    4382                 :             :     else
    4383                 :       31095 :         tcount = 0;
    4384                 :             : 
    4385                 :             :     /*
    4386                 :             :      * Execute the plan
    4387                 :             :      */
    4388                 :       39624 :     rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
    4389                 :       39624 :                                          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   [ +  +  +  -  :       37582 :     switch (rc)
                +  +  - ]
    4397                 :             :     {
    4398                 :        5454 :         case SPI_OK_SELECT:
    4399                 :             :             Assert(!stmt->mod_stmt);
    4400                 :        5454 :             exec_set_found(estate, (SPI_processed != 0));
    4401                 :        5454 :             break;
    4402                 :             : 
    4403                 :       19985 :         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                 :       19985 :             exec_set_found(estate, (SPI_processed != 0));
    4413                 :       19985 :             break;
    4414                 :             : 
    4415                 :       12140 :         case SPI_OK_SELINTO:
    4416                 :             :         case SPI_OK_UTILITY:
    4417                 :             :             Assert(!stmt->mod_stmt);
    4418                 :       12140 :             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                 :       37579 :     estate->eval_processed = SPI_processed;
    4452                 :             : 
    4453                 :             :     /* Process INTO if present */
    4454         [ +  + ]:       37579 :     if (stmt->into)
    4455                 :             :     {
    4456                 :        6532 :         SPITupleTable *tuptab = SPI_tuptable;
    4457                 :        6532 :         uint64      n = SPI_processed;
    4458                 :             :         PLpgSQL_variable *target;
    4459                 :             : 
    4460                 :             :         /* If the statement did not return a tuple table, complain */
    4461         [ -  + ]:        6532 :         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                 :        6532 :         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         [ +  + ]:        6532 :         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   [ +  +  +  +  :        6491 :             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                 :        6463 :             exec_move_row(estate, target, tuptab->vals[0], tuptab->tupdesc);
    4515                 :             :         }
    4516                 :             : 
    4517                 :             :         /* Clean up */
    4518                 :        6476 :         exec_eval_cleanup(estate);
    4519                 :        6476 :         SPI_freetuptable(SPI_tuptable);
    4520                 :             :     }
    4521                 :             :     else
    4522                 :             :     {
    4523                 :             :         /* If the statement returned a tuple table, complain */
    4524         [ -  + ]:       31047 :         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                 :       37523 :     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                 :       11148 : 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                 :       11148 :     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                 :       11148 :     query = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod);
    4559         [ -  + ]:       11148 :     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                 :       11148 :     querystr = convert_value_to_string(estate, query, restype);
    4566                 :             : 
    4567                 :             :     /* copy it into the stmt_mcontext before we clean up */
    4568                 :       11148 :     querystr = MemoryContextStrdup(stmt_mcontext, querystr);
    4569                 :             : 
    4570                 :       11148 :     exec_eval_cleanup(estate);
    4571                 :             : 
    4572                 :             :     /*
    4573                 :             :      * Execute the query without preparing a saved plan.
    4574                 :             :      */
    4575                 :       11148 :     paramLI = exec_eval_using_params(estate, stmt->params);
    4576                 :             : 
    4577                 :       11148 :     memset(&options, 0, sizeof(options));
    4578                 :       11148 :     options.params = paramLI;
    4579                 :       11148 :     options.read_only = estate->readonly_func;
    4580                 :             : 
    4581                 :       11148 :     exec_res = SPI_execute_extended(querystr, &options);
    4582                 :             : 
    4583   [ +  -  -  +  :       10993 :     switch (exec_res)
                   +  - ]
    4584                 :             :     {
    4585                 :       10990 :         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                 :       10990 :             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                 :       10990 :     estate->eval_processed = SPI_processed;
    4642                 :             : 
    4643                 :             :     /* Process INTO if present */
    4644         [ +  + ]:       10990 :     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                 :       10970 :     SPI_freetuptable(SPI_tuptable);
    4717                 :       10970 :     MemoryContextReset(stmt_mcontext);
    4718                 :             : 
    4719                 :       10970 :     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                 :        6390 : exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
    4732                 :             : {
    4733                 :             :     Portal      portal;
    4734                 :             :     int         rc;
    4735                 :             : 
    4736                 :        6390 :     portal = exec_dynquery_with_params(estate, stmt->query, stmt->params,
    4737                 :             :                                        NULL, CURSOR_OPT_NO_SCROLL);
    4738                 :             : 
    4739                 :             :     /*
    4740                 :             :      * Execute the loop
    4741                 :             :      */
    4742                 :        6390 :     rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, true);
    4743                 :             : 
    4744                 :             :     /*
    4745                 :             :      * Close the implicit cursor
    4746                 :             :      */
    4747                 :        6386 :     SPI_cursor_close(portal);
    4748                 :             : 
    4749                 :        6386 :     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                 :          56 : exec_stmt_rollback(PLpgSQL_execstate *estate, PLpgSQL_stmt_rollback *stmt)
    5082                 :             : {
    5083         [ +  + ]:          56 :     if (stmt->chain)
    5084                 :           2 :         SPI_rollback_and_chain();
    5085                 :             :     else
    5086                 :          54 :         SPI_rollback();
    5087                 :             : 
    5088                 :             :     /*
    5089                 :             :      * We need to build new simple-expression infrastructure, since the old
    5090                 :             :      * data structures are gone.
    5091                 :             :      */
    5092                 :          53 :     estate->simple_eval_estate = NULL;
    5093                 :          53 :     estate->simple_eval_resowner = NULL;
    5094                 :          53 :     plpgsql_create_econtext(estate);
    5095                 :             : 
    5096                 :          53 :     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                 :       66456 : 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         [ +  + ]:       66456 :     if (expr->plan == NULL)
    5116                 :        2782 :         exec_prepare_plan(estate, expr, 0);
    5117                 :             : 
    5118                 :       66434 :     value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
    5119                 :       66311 :     exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
    5120                 :       66277 :     exec_eval_cleanup(estate);
    5121                 :       66277 : }
    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                 :      116385 : exec_assign_value(PLpgSQL_execstate *estate,
    5163                 :             :                   PLpgSQL_datum *target,
    5164                 :             :                   Datum value, bool isNull,
    5165                 :             :                   Oid valtype, int32 valtypmod)
    5166                 :             : {
    5167   [ +  +  +  +  :      116385 :     switch (target->dtype)
                      - ]
    5168                 :             :     {
    5169                 :      114392 :         case PLPGSQL_DTYPE_VAR:
    5170                 :             :         case PLPGSQL_DTYPE_PROMISE:
    5171                 :             :             {
    5172                 :             :                 /*
    5173                 :             :                  * Target is a variable
    5174                 :             :                  */
    5175                 :      114392 :                 PLpgSQL_var *var = (PLpgSQL_var *) target;
    5176                 :             :                 Datum       newvalue;
    5177                 :             : 
    5178                 :      114392 :                 newvalue = exec_cast_value(estate,
    5179                 :             :                                            value,
    5180                 :             :                                            &isNull,
    5181                 :             :                                            valtype,
    5182                 :             :                                            valtypmod,
    5183                 :      114392 :                                            var->datatype->typoid,
    5184                 :      114392 :                                            var->datatype->atttypmod);
    5185                 :             : 
    5186   [ +  +  +  + ]:      114376 :                 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   [ +  +  +  + ]:      114370 :                 if (!var->datatype->typbyval && !isNull)
    5208                 :             :                 {
    5209         [ +  + ]:       78004 :                     if (var->datatype->typisarray &&
    5210         [ +  + ]:        6954 :                         !VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(newvalue)))
    5211                 :             :                     {
    5212                 :             :                         /* array and not already R/W, so apply expand_array */
    5213                 :        6829 :                         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                 :       71175 :                         newvalue = datumTransfer(newvalue,
    5221                 :             :                                                  false,
    5222                 :       71175 :                                                  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   [ +  +  +  +  :      114370 :                 if (var->value != newvalue || var->isnull || isNull)
                   +  + ]
    5239                 :      112679 :                     assign_simple_var(estate, var, newvalue, isNull,
    5240   [ +  +  +  + ]:      112679 :                                       (!var->datatype->typbyval && !isNull));
    5241                 :             :                 else
    5242                 :        1691 :                     var->promise = PLPGSQL_PROMISE_NONE;
    5243                 :      114370 :                 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                 :        1527 :         case PLPGSQL_DTYPE_RECFIELD:
    5305                 :             :             {
    5306                 :             :                 /*
    5307                 :             :                  * Target is a field of a record
    5308                 :             :                  */
    5309                 :        1527 :                 PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target;
    5310                 :             :                 PLpgSQL_rec *rec;
    5311                 :             :                 ExpandedRecordHeader *erh;
    5312                 :             : 
    5313                 :        1527 :                 rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    5314                 :        1527 :                 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         [ +  + ]:        1527 :                 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         [ +  + ]:        1526 :                 if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
    5333                 :             :                 {
    5334         [ +  + ]:          27 :                     if (!expanded_record_lookup_field(erh,
    5335                 :          27 :                                                       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                 :          26 :                     recfield->rectupledescid = erh->er_tupdesc_id;
    5342                 :             :                 }
    5343                 :             : 
    5344                 :             :                 /* We don't support assignments to system columns. */
    5345         [ -  + ]:        1525 :                 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                 :        1525 :                 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                 :        1525 :                 expanded_record_set_field(erh, recfield->finfo.fnumber,
    5362                 :             :                                           value, isNull, !estate->atomic);
    5363                 :        1522 :                 break;
    5364                 :             :             }
    5365                 :             : 
    5366                 :           0 :         default:
    5367         [ #  # ]:           0 :             elog(ERROR, "unrecognized dtype: %d", target->dtype);
    5368                 :             :     }
    5369                 :      116345 : }
    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                 :       46970 : 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   [ +  +  +  +  :       46970 :     switch (datum->dtype)
                   +  - ]
    5399                 :             :     {
    5400                 :       16864 :         case PLPGSQL_DTYPE_PROMISE:
    5401                 :             :             /* fulfill promise if needed, then handle like regular var */
    5402                 :       16864 :             plpgsql_fulfill_promise(estate, (PLpgSQL_var *) datum);
    5403                 :             : 
    5404                 :             :             pg_fallthrough;
    5405                 :             : 
    5406                 :       29712 :         case PLPGSQL_DTYPE_VAR:
    5407                 :             :             {
    5408                 :       29712 :                 PLpgSQL_var *var = (PLpgSQL_var *) datum;
    5409                 :             : 
    5410                 :       29712 :                 *typeid = var->datatype->typoid;
    5411                 :       29712 :                 *typetypmod = var->datatype->atttypmod;
    5412                 :       29712 :                 *value = var->value;
    5413                 :       29712 :                 *isnull = var->isnull;
    5414                 :       29712 :                 break;
    5415                 :             :             }
    5416                 :             : 
    5417                 :        3258 :         case PLPGSQL_DTYPE_ROW:
    5418                 :             :             {
    5419                 :        3258 :                 PLpgSQL_row *row = (PLpgSQL_row *) datum;
    5420                 :             :                 HeapTuple   tup;
    5421                 :             : 
    5422                 :             :                 /* We get here if there are multiple OUT parameters */
    5423         [ -  + ]:        3258 :                 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                 :        3258 :                 BlessTupleDesc(row->rowtupdesc);
    5427                 :        3258 :                 oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    5428                 :        3258 :                 tup = make_tuple_from_row(estate, row, row->rowtupdesc);
    5429         [ -  + ]:        3258 :                 if (tup == NULL)    /* should not happen */
    5430         [ #  # ]:           0 :                     elog(ERROR, "row not compatible with its own tupdesc");
    5431                 :        3258 :                 *typeid = row->rowtupdesc->tdtypeid;
    5432                 :        3258 :                 *typetypmod = row->rowtupdesc->tdtypmod;
    5433                 :        3258 :                 *value = HeapTupleGetDatum(tup);
    5434                 :        3258 :                 *isnull = false;
    5435                 :        3258 :                 MemoryContextSwitchTo(oldcontext);
    5436                 :        3258 :                 break;
    5437                 :             :             }
    5438                 :             : 
    5439                 :       12421 :         case PLPGSQL_DTYPE_REC:
    5440                 :             :             {
    5441                 :       12421 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
    5442                 :             : 
    5443         [ +  + ]:       12421 :                 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         [ +  + ]:       12297 :                     if (ExpandedRecordIsEmpty(rec->erh))
    5455                 :             :                     {
    5456                 :             :                         /* Empty record is also a NULL */
    5457                 :         223 :                         *value = (Datum) 0;
    5458                 :         223 :                         *isnull = true;
    5459                 :             :                     }
    5460                 :             :                     else
    5461                 :             :                     {
    5462                 :       12074 :                         *value = ExpandedRecordGetDatum(rec->erh);
    5463                 :       12074 :                         *isnull = false;
    5464                 :             :                     }
    5465         [ +  + ]:       12297 :                     if (rec->rectypeid != RECORDOID)
    5466                 :             :                     {
    5467                 :             :                         /* Report variable's declared type, if not RECORD */
    5468                 :        1753 :                         *typeid = rec->rectypeid;
    5469                 :        1753 :                         *typetypmod = -1;
    5470                 :             :                     }
    5471                 :             :                     else
    5472                 :             :                     {
    5473                 :             :                         /* Report record's actual type if declared RECORD */
    5474                 :       10544 :                         *typeid = rec->erh->er_typeid;
    5475                 :       10544 :                         *typetypmod = rec->erh->er_typmod;
    5476                 :             :                     }
    5477                 :             :                 }
    5478                 :       12421 :                 break;
    5479                 :             :             }
    5480                 :             : 
    5481                 :        1579 :         case PLPGSQL_DTYPE_RECFIELD:
    5482                 :             :             {
    5483                 :        1579 :                 PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
    5484                 :             :                 PLpgSQL_rec *rec;
    5485                 :             :                 ExpandedRecordHeader *erh;
    5486                 :             : 
    5487                 :        1579 :                 rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    5488                 :        1579 :                 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         [ -  + ]:        1579 :                 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         [ -  + ]:        1579 :                 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                 :        1579 :                 *typeid = recfield->finfo.ftypeid;
    5519                 :        1579 :                 *typetypmod = recfield->finfo.ftypmod;
    5520                 :             : 
    5521                 :             :                 /* And fetch the field value. */
    5522                 :        1579 :                 *value = expanded_record_get_field(erh,
    5523                 :             :                                                    recfield->finfo.fnumber,
    5524                 :             :                                                    isnull);
    5525                 :        1579 :                 break;
    5526                 :             :             }
    5527                 :             : 
    5528                 :           0 :         default:
    5529         [ #  # ]:           0 :             elog(ERROR, "unrecognized dtype: %d", datum->dtype);
    5530                 :             :     }
    5531                 :       46970 : }
    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                 :       22956 : plpgsql_exec_get_datum_type_info(PLpgSQL_execstate *estate,
    5626                 :             :                                  PLpgSQL_datum *datum,
    5627                 :             :                                  Oid *typeId, int32 *typMod, Oid *collation)
    5628                 :             : {
    5629   [ +  +  +  - ]:       22956 :     switch (datum->dtype)
    5630                 :             :     {
    5631                 :       17711 :         case PLPGSQL_DTYPE_VAR:
    5632                 :             :         case PLPGSQL_DTYPE_PROMISE:
    5633                 :             :             {
    5634                 :       17711 :                 PLpgSQL_var *var = (PLpgSQL_var *) datum;
    5635                 :             : 
    5636                 :       17711 :                 *typeId = var->datatype->typoid;
    5637                 :       17711 :                 *typMod = var->datatype->atttypmod;
    5638                 :       17711 :                 *collation = var->datatype->collation;
    5639                 :       17711 :                 break;
    5640                 :             :             }
    5641                 :             : 
    5642                 :        1633 :         case PLPGSQL_DTYPE_REC:
    5643                 :             :             {
    5644                 :        1633 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
    5645                 :             : 
    5646   [ +  +  +  + ]:        1633 :                 if (rec->erh == NULL || rec->rectypeid != RECORDOID)
    5647                 :             :                 {
    5648                 :             :                     /* Report variable's declared type */
    5649                 :         323 :                     *typeId = rec->rectypeid;
    5650                 :         323 :                     *typMod = -1;
    5651                 :             :                 }
    5652                 :             :                 else
    5653                 :             :                 {
    5654                 :             :                     /* Report record's actual type if declared RECORD */
    5655                 :        1310 :                     *typeId = rec->erh->er_typeid;
    5656                 :             :                     /* do NOT return the mutable typmod of a RECORD variable */
    5657                 :        1310 :                     *typMod = -1;
    5658                 :             :                 }
    5659                 :             :                 /* composite types are never collatable */
    5660                 :        1633 :                 *collation = InvalidOid;
    5661                 :        1633 :                 break;
    5662                 :             :             }
    5663                 :             : 
    5664                 :        3612 :         case PLPGSQL_DTYPE_RECFIELD:
    5665                 :             :             {
    5666                 :        3612 :                 PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
    5667                 :             :                 PLpgSQL_rec *rec;
    5668                 :             : 
    5669                 :        3612 :                 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         [ +  + ]:        3612 :                 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         [ +  + ]:        3611 :                 if (unlikely(recfield->rectupledescid != rec->erh->er_tupdesc_id))
    5684                 :             :                 {
    5685         [ +  + ]:        2094 :                     if (!expanded_record_lookup_field(rec->erh,
    5686                 :        2094 :                                                       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                 :        2084 :                     recfield->rectupledescid = rec->erh->er_tupdesc_id;
    5693                 :             :                 }
    5694                 :             : 
    5695                 :        3601 :                 *typeId = recfield->finfo.ftypeid;
    5696                 :        3601 :                 *typMod = recfield->finfo.ftypmod;
    5697                 :        3601 :                 *collation = recfield->finfo.fcollation;
    5698                 :        3601 :                 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                 :       22945 : }
    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                 :       85663 : 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                 :       85663 :     exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
    5752                 :       85663 :     exprdatum = exec_cast_value(estate, exprdatum, isNull,
    5753                 :             :                                 exprtypeid, exprtypmod,
    5754                 :             :                                 BOOLOID, -1);
    5755                 :       85663 :     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                 :      227271 : exec_eval_expr(PLpgSQL_execstate *estate,
    5767                 :             :                PLpgSQL_expr *expr,
    5768                 :             :                bool *isNull,
    5769                 :             :                Oid *rettype,
    5770                 :             :                int32 *rettypmod)
    5771                 :             : {
    5772                 :      227271 :     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         [ +  + ]:      227271 :     if (expr->plan == NULL)
    5780                 :       12792 :         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         [ +  + ]:      227247 :     if (exec_eval_simple_expr(estate, expr,
    5787                 :             :                               &result, isNull, rettype, rettypmod))
    5788                 :      221793 :         return result;
    5789                 :             : 
    5790                 :             :     /*
    5791                 :             :      * Else do it the hard way via exec_run_select
    5792                 :             :      */
    5793                 :        5294 :     rc = exec_run_select(estate, expr, 0, NULL);
    5794         [ -  + ]:        5277 :     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         [ -  + ]:        5277 :     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                 :        5277 :     attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
    5816                 :        5277 :     *rettype = attr->atttypid;
    5817                 :        5277 :     *rettypmod = attr->atttypmod;
    5818                 :             : 
    5819                 :             :     /*
    5820                 :             :      * If there are no rows selected, the result is a NULL of that type.
    5821                 :             :      */
    5822         [ -  + ]:        5277 :     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         [ +  + ]:        5277 :     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                 :        5276 :     return SPI_getbinval(estate->eval_tuptable->vals[0],
    5841                 :        5276 :                          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                 :       10866 : 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         [ +  + ]:       10866 :     if (expr->plan == NULL)
    5872                 :             :     {
    5873                 :         700 :         int         cursorOptions = CURSOR_OPT_NO_SCROLL;
    5874                 :             : 
    5875         [ +  + ]:         700 :         if (portalP == NULL)
    5876                 :         503 :             cursorOptions |= CURSOR_OPT_PARALLEL_OK;
    5877                 :         700 :         exec_prepare_plan(estate, expr, cursorOptions);
    5878                 :             :     }
    5879                 :             : 
    5880                 :             :     /*
    5881                 :             :      * Set up ParamListInfo to pass to executor
    5882                 :             :      */
    5883                 :       10837 :     paramLI = setup_param_list(estate, expr);
    5884                 :             : 
    5885                 :             :     /*
    5886                 :             :      * If a portal was requested, put the query and paramlist into the portal
    5887                 :             :      */
    5888         [ +  + ]:       10837 :     if (portalP != NULL)
    5889                 :             :     {
    5890                 :        3268 :         *portalP = SPI_cursor_open_with_paramlist(NULL, expr->plan,
    5891                 :             :                                                   paramLI,
    5892                 :        1634 :                                                   estate->readonly_func);
    5893         [ -  + ]:        1634 :         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                 :        1634 :         exec_eval_cleanup(estate);
    5897                 :        1634 :         return SPI_OK_CURSOR;
    5898                 :             :     }
    5899                 :             : 
    5900                 :             :     /*
    5901                 :             :      * Execute the query
    5902                 :             :      */
    5903                 :        9203 :     rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
    5904                 :        9203 :                                          estate->readonly_func, maxtuples);
    5905         [ -  + ]:        8213 :     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                 :        8213 :     estate->eval_tuptable = SPI_tuptable;
    5926                 :        8213 :     estate->eval_processed = SPI_processed;
    5927                 :             : 
    5928                 :        8213 :     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                 :        8093 : 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                 :        8093 :     bool        found = false;
    5944                 :        8093 :     int         rc = PLPGSQL_RC_OK;
    5945                 :        8093 :     uint64      previous_id = INVALID_TUPLEDESC_IDENTIFIER;
    5946                 :        8093 :     bool        tupdescs_match = true;
    5947                 :             :     uint64      n;
    5948                 :             : 
    5949                 :             :     /* Fetch loop variable's datum entry */
    5950                 :        8093 :     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                 :        8093 :     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         [ +  + ]:        8093 :     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         [ +  + ]:        8093 :     SPI_cursor_fetch(portal, true, prefetch_ok ? 10 : 1);
    5975                 :        8089 :     tuptab = SPI_tuptable;
    5976                 :        8089 :     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         [ +  + ]:        8089 :     if (n == 0)
    5983                 :             :     {
    5984                 :        1149 :         exec_move_row(estate, var, NULL, tuptab->tupdesc);
    5985                 :        1149 :         exec_eval_cleanup(estate);
    5986                 :             :     }
    5987                 :             :     else
    5988                 :        6940 :         found = true;           /* processed at least one tuple */
    5989                 :             : 
    5990                 :             :     /*
    5991                 :             :      * Now do the loop
    5992                 :             :      */
    5993         [ +  + ]:       29332 :     while (n > 0)
    5994                 :             :     {
    5995                 :             :         uint64      i;
    5996                 :             : 
    5997         [ +  + ]:       57004 :         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         [ +  + ]:       35761 :             if (var->dtype == PLPGSQL_DTYPE_REC)
    6011                 :             :             {
    6012                 :        4596 :                 PLpgSQL_rec *rec = (PLpgSQL_rec *) var;
    6013                 :             : 
    6014         [ +  + ]:        4596 :                 if (rec->erh &&
    6015   [ +  +  +  + ]:        4040 :                     rec->erh->er_tupdesc_id == previous_id &&
    6016                 :             :                     tupdescs_match)
    6017                 :             :                 {
    6018                 :             :                     /* Only need to assign a new tuple value */
    6019                 :        3992 :                     expanded_record_set_tuple(rec->erh, tuptab->vals[i],
    6020                 :        3992 :                                               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                 :         604 :                     exec_move_row(estate, var,
    6030                 :         604 :                                   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         [ +  + ]:         603 :                     if (tupdescs_match)
    6038                 :             :                     {
    6039                 :         599 :                         tupdescs_match =
    6040                 :         611 :                             (rec->rectypeid == RECORDOID ||
    6041   [ +  +  +  -  :         611 :                              rec->rectypeid == tuptab->tupdesc->tdtypeid ||
                   +  + ]
    6042                 :          12 :                              compatible_tupdescs(tuptab->tupdesc,
    6043                 :             :                                                  expanded_record_get_tupdesc(rec->erh)));
    6044                 :             :                     }
    6045                 :         603 :                     previous_id = rec->erh->er_tupdesc_id;
    6046                 :             :                 }
    6047                 :             :             }
    6048                 :             :             else
    6049                 :       31165 :                 exec_move_row(estate, var, tuptab->vals[i], tuptab->tupdesc);
    6050                 :             : 
    6051                 :       35759 :             exec_eval_cleanup(estate);
    6052                 :             : 
    6053                 :             :             /*
    6054                 :             :              * Execute the statements
    6055                 :             :              */
    6056                 :       35759 :             rc = exec_stmts(estate, stmt->body);
    6057                 :             : 
    6058   [ +  +  -  +  :       35741 :             LOOP_RC_PROCESSING(stmt->label, goto loop_exit);
          -  -  -  -  -  
          -  +  +  +  -  
             -  -  -  - ]
    6059                 :             :         }
    6060                 :             : 
    6061                 :       21243 :         SPI_freetuptable(tuptab);
    6062                 :             : 
    6063                 :             :         /*
    6064                 :             :          * Fetch more tuples.  If prefetching is allowed, grab 50 at a time.
    6065                 :             :          */
    6066         [ +  + ]:       21243 :         SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
    6067                 :       21243 :         tuptab = SPI_tuptable;
    6068                 :       21243 :         n = SPI_processed;
    6069                 :             :     }
    6070                 :             : 
    6071                 :        7820 : loop_exit:
    6072                 :             : 
    6073                 :             :     /*
    6074                 :             :      * Release last group of tuples (if any)
    6075                 :             :      */
    6076                 :        8069 :     SPI_freetuptable(tuptab);
    6077                 :             : 
    6078                 :        8069 :     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                 :        8069 :     exec_set_found(estate, found);
    6087                 :             : 
    6088                 :        8069 :     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                 :      227247 : 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                 :      227247 :     ExprContext *econtext = estate->eval_econtext;
    6128                 :      227247 :     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         [ +  + ]:      227247 :     if (expr->expr_simple_expr == NULL)
    6138                 :        4923 :         return false;
    6139                 :             : 
    6140                 :             :     /*
    6141                 :             :      * If expression is in use in current xact, don't touch it.
    6142                 :             :      */
    6143         [ +  + ]:      222324 :     if (unlikely(expr->expr_simple_in_use) &&
    6144         [ +  + ]:         415 :         expr->expr_simple_lxid == curlxid)
    6145                 :         370 :         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                 :      221954 :     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   [ +  +  +  + ]:      221954 :     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                 :      218639 :         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         [ +  + ]:        3315 :         if (expr->expr_simple_plan_lxid == curlxid)
    6183                 :        1343 :             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                 :        3315 :         expr->expr_simple_expr = NULL;
    6194                 :        3315 :         expr->expr_rwopt = PLPGSQL_RWOPT_UNKNOWN;
    6195                 :        3315 :         expr->expr_rw_param = NULL;
    6196                 :        3315 :         expr->expr_simple_plan = NULL;
    6197                 :        3315 :         expr->expr_simple_plan_lxid = InvalidLocalTransactionId;
    6198                 :             : 
    6199                 :             :         /* Do the replanning work in the eval_mcontext */
    6200                 :        3315 :         oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    6201                 :        3315 :         cplan = SPI_plan_get_cached_plan(expr->plan);
    6202                 :        3315 :         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   [ +  +  +  - ]:        6629 :         if (exec_is_simple_query(expr) &&
    6221                 :        3314 :             CachedPlanAllowsSimpleValidityCheck(expr->expr_simple_plansource,
    6222                 :             :                                                 cplan,
    6223                 :             :                                                 estate->simple_eval_resowner))
    6224                 :             :         {
    6225                 :             :             /* Remember that we have the refcount */
    6226                 :        3314 :             expr->expr_simple_plan = cplan;
    6227                 :        3314 :             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                 :        3314 :         ReleaseCachedPlan(cplan, CurrentResourceOwner);
    6241                 :             : 
    6242                 :             :         /* Extract desired scalar expression from cached plan */
    6243                 :        3314 :         exec_save_simple_expr(expr, cplan);
    6244                 :             :     }
    6245                 :             : 
    6246                 :             :     /*
    6247                 :             :      * Pass back previously-determined result type.
    6248                 :             :      */
    6249                 :      221953 :     *rettype = expr->expr_simple_type;
    6250                 :      221953 :     *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                 :      221953 :     paramLI = estate->paramLI;
    6257                 :      221953 :     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                 :      221953 :     paramLI->parserSetupArg = expr;
    6266                 :      221953 :     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         [ +  + ]:      221953 :     if (unlikely(expr->expr_simple_lxid != curlxid))
    6274                 :             :     {
    6275                 :       52945 :         oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
    6276                 :       52945 :         expr->expr_simple_state =
    6277                 :       52945 :             ExecInitExprWithParams(expr->expr_simple_expr,
    6278                 :             :                                    econtext->ecxt_param_list_info);
    6279                 :       52945 :         expr->expr_simple_in_use = false;
    6280                 :       52945 :         expr->expr_simple_lxid = curlxid;
    6281                 :       52945 :         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                 :      221953 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    6297   [ +  +  +  + ]:      221953 :     need_snapshot = (expr->expr_simple_mutable && !estate->readonly_func);
    6298         [ +  + ]:      221953 :     if (need_snapshot)
    6299                 :             :     {
    6300                 :       24408 :         CommandCounterIncrement();
    6301                 :       24408 :         PushActiveSnapshot(GetTransactionSnapshot());
    6302                 :             :     }
    6303                 :             : 
    6304                 :             :     /*
    6305                 :             :      * Mark expression as busy for the duration of the ExecEvalExpr call.
    6306                 :             :      */
    6307                 :      221953 :     expr->expr_simple_in_use = true;
    6308                 :             : 
    6309                 :             :     /*
    6310                 :             :      * Finally we can call the executor to evaluate the expression
    6311                 :             :      */
    6312                 :      221953 :     *result = ExecEvalExpr(expr->expr_simple_state,
    6313                 :             :                            econtext,
    6314                 :             :                            isNull);
    6315                 :             : 
    6316                 :             :     /* Assorted cleanup */
    6317                 :      221793 :     expr->expr_simple_in_use = false;
    6318                 :             : 
    6319                 :      221793 :     econtext->ecxt_param_list_info = NULL;
    6320                 :             : 
    6321                 :      221793 :     paramLI->parserSetupArg = save_setup_arg;
    6322                 :             : 
    6323         [ +  + ]:      221793 :     if (need_snapshot)
    6324                 :       24374 :         PopActiveSnapshot();
    6325                 :             : 
    6326                 :      221793 :     MemoryContextSwitchTo(oldcontext);
    6327                 :             : 
    6328                 :             :     /*
    6329                 :             :      * That's it.
    6330                 :             :      */
    6331                 :      221793 :     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                 :       52321 : 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         [ +  + ]:       52321 :     if (!bms_is_empty(expr->paramnos))
    6365                 :             :     {
    6366                 :             :         /* Use the common ParamListInfo */
    6367                 :       22397 :         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                 :       22397 :         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                 :       29924 :         paramLI = NULL;
    6384                 :             :     }
    6385                 :       52321 :     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                 :        7202 : 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                 :        7202 :     bool        ok = true;
    6408                 :             :     int32       prmtypmod;
    6409                 :             : 
    6410                 :             :     /* paramid's are 1-based, but dnos are 0-based */
    6411                 :        7202 :     dno = paramid - 1;
    6412                 :             :     Assert(dno >= 0 && dno < params->numParams);
    6413                 :             : 
    6414                 :             :     /* fetch back the hook data */
    6415                 :        7202 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6416                 :        7202 :     expr = (PLpgSQL_expr *) params->parserSetupArg;
    6417                 :             :     Assert(params->numParams == estate->ndatums);
    6418                 :             : 
    6419                 :             :     /* now we can access the target datum */
    6420                 :        7202 :     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         [ +  + ]:        7202 :     if (!bms_is_member(dno, expr->paramnos))
    6430                 :        2241 :         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         [ +  + ]:        4961 :     else if (speculative)
    6437                 :             :     {
    6438   [ +  -  +  +  :        4313 :         switch (datum->dtype)
                      - ]
    6439                 :             :         {
    6440                 :        2470 :             case PLPGSQL_DTYPE_VAR:
    6441                 :             :             case PLPGSQL_DTYPE_PROMISE:
    6442                 :             :                 /* always safe */
    6443                 :        2470 :                 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                 :        1539 :             case PLPGSQL_DTYPE_RECFIELD:
    6454                 :             :                 {
    6455                 :        1539 :                     PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
    6456                 :             :                     PLpgSQL_rec *rec;
    6457                 :             : 
    6458                 :        1539 :                     rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    6459                 :             : 
    6460                 :             :                     /*
    6461                 :             :                      * If record variable is NULL, don't risk anything.
    6462                 :             :                      */
    6463         [ -  + ]:        1539 :                     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         [ +  + ]:        1539 :                     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                 :        1539 :                     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         [ +  + ]:        7202 :     if (!ok)
    6490                 :             :     {
    6491                 :        2241 :         prm->value = (Datum) 0;
    6492                 :        2241 :         prm->isnull = true;
    6493                 :        2241 :         prm->pflags = 0;
    6494                 :        2241 :         prm->ptype = InvalidOid;
    6495                 :        2241 :         return prm;
    6496                 :             :     }
    6497                 :             : 
    6498                 :             :     /* OK, evaluate the value and store into the return struct */
    6499                 :        4961 :     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                 :        4961 :     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         [ +  + ]:        4961 :     if (datum->dtype == PLPGSQL_DTYPE_VAR)
    6511   [ +  +  +  + ]:        2948 :         prm->value = MakeExpandedObjectReadOnly(prm->value,
    6512                 :             :                                                 prm->isnull,
    6513                 :             :                                                 ((PLpgSQL_var *) datum)->datatype->typlen);
    6514         [ +  + ]:        2013 :     else if (datum->dtype == PLPGSQL_DTYPE_REC)
    6515         [ -  + ]:         304 :         prm->value = MakeExpandedObjectReadOnly(prm->value,
    6516                 :             :                                                 prm->isnull,
    6517                 :             :                                                 -1);
    6518                 :             : 
    6519                 :        4961 :     return prm;
    6520                 :             : }
    6521                 :             : 
    6522                 :             : /*
    6523                 :             :  * plpgsql_param_compile        paramCompile callback for plpgsql parameters
    6524                 :             :  */
    6525                 :             : static void
    6526                 :       96706 : 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                 :       96706 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6538                 :       96706 :     expr = (PLpgSQL_expr *) params->parserSetupArg;
    6539                 :             : 
    6540                 :             :     /* paramid's are 1-based, but dnos are 0-based */
    6541                 :       96706 :     dno = param->paramid - 1;
    6542                 :             :     Assert(dno >= 0 && dno < estate->ndatums);
    6543                 :             : 
    6544                 :             :     /* now we can access the target datum */
    6545                 :       96706 :     datum = estate->datums[dno];
    6546                 :             : 
    6547                 :       96706 :     scratch.opcode = EEOP_PARAM_CALLBACK;
    6548                 :       96706 :     scratch.resvalue = resv;
    6549                 :       96706 :     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         [ +  + ]:       96706 :     if (datum->dtype == PLPGSQL_DTYPE_VAR)
    6567                 :             :     {
    6568                 :       61532 :         bool        isvarlena = (((PLpgSQL_var *) datum)->datatype->typlen == -1);
    6569                 :             : 
    6570   [ +  +  +  +  :       61532 :         if (isvarlena && dno == expr->target_param && expr->expr_simple_expr)
                   +  - ]
    6571                 :        1940 :             scratch.d.cparam.paramfunc = plpgsql_param_eval_var_check;
    6572         [ +  + ]:       59592 :         else if (isvarlena)
    6573                 :       40749 :             scratch.d.cparam.paramfunc = plpgsql_param_eval_var_ro;
    6574                 :             :         else
    6575                 :       18843 :             scratch.d.cparam.paramfunc = plpgsql_param_eval_var;
    6576                 :             :     }
    6577         [ +  + ]:       35174 :     else if (datum->dtype == PLPGSQL_DTYPE_RECFIELD)
    6578                 :       17654 :         scratch.d.cparam.paramfunc = plpgsql_param_eval_recfield;
    6579         [ +  + ]:       17520 :     else if (datum->dtype == PLPGSQL_DTYPE_PROMISE)
    6580                 :             :     {
    6581         [ +  + ]:       14899 :         if (((PLpgSQL_var *) datum)->datatype->typlen == -1)
    6582                 :       13041 :             scratch.d.cparam.paramfunc = plpgsql_param_eval_generic_ro;
    6583                 :             :         else
    6584                 :        1858 :             scratch.d.cparam.paramfunc = plpgsql_param_eval_generic;
    6585                 :             :     }
    6586         [ +  - ]:        2621 :     else if (datum->dtype == PLPGSQL_DTYPE_REC)
    6587                 :        2621 :         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                 :       96706 :     scratch.d.cparam.paramarg = expr;
    6600                 :       96706 :     scratch.d.cparam.paramarg2 = param;
    6601                 :       96706 :     scratch.d.cparam.paramid = param->paramid;
    6602                 :       96706 :     scratch.d.cparam.paramtype = param->paramtype;
    6603                 :       96706 :     ExprEvalPushStep(state, &scratch);
    6604                 :       96706 : }
    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                 :       21116 : plpgsql_param_eval_var_check(ExprState *state, ExprEvalStep *op,
    6621                 :             :                              ExprContext *econtext)
    6622                 :             : {
    6623                 :             :     ParamListInfo params;
    6624                 :             :     PLpgSQL_execstate *estate;
    6625                 :       21116 :     int         dno = op->d.cparam.paramid - 1;
    6626                 :             :     PLpgSQL_var *var;
    6627                 :             : 
    6628                 :             :     /* fetch back the hook data */
    6629                 :       21116 :     params = econtext->ecxt_param_list_info;
    6630                 :       21116 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6631                 :             :     Assert(dno >= 0 && dno < estate->ndatums);
    6632                 :             : 
    6633                 :             :     /* now we can access the target datum */
    6634                 :       21116 :     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   [ +  +  +  + ]:       42191 :     if (!var->isnull &&
    6642                 :       21075 :         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                 :       21010 :     *op->resvalue = var->value;
    6700                 :       21010 :     *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                 :      108339 : plpgsql_param_eval_var(ExprState *state, ExprEvalStep *op,
    6774                 :             :                        ExprContext *econtext)
    6775                 :             : {
    6776                 :             :     ParamListInfo params;
    6777                 :             :     PLpgSQL_execstate *estate;
    6778                 :      108339 :     int         dno = op->d.cparam.paramid - 1;
    6779                 :             :     PLpgSQL_var *var;
    6780                 :             : 
    6781                 :             :     /* fetch back the hook data */
    6782                 :      108339 :     params = econtext->ecxt_param_list_info;
    6783                 :      108339 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6784                 :             :     Assert(dno >= 0 && dno < estate->ndatums);
    6785                 :             : 
    6786                 :             :     /* now we can access the target datum */
    6787                 :      108339 :     var = (PLpgSQL_var *) estate->datums[dno];
    6788                 :             :     Assert(var->dtype == PLPGSQL_DTYPE_VAR);
    6789                 :             : 
    6790                 :             :     /* inlined version of exec_eval_datum() */
    6791                 :      108339 :     *op->resvalue = var->value;
    6792                 :      108339 :     *op->resnull = var->isnull;
    6793                 :             : 
    6794                 :             :     /* safety check -- an assertion should be sufficient */
    6795                 :             :     Assert(var->datatype->typoid == op->d.cparam.paramtype);
    6796                 :      108339 : }
    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                 :       98874 : plpgsql_param_eval_var_ro(ExprState *state, ExprEvalStep *op,
    6806                 :             :                           ExprContext *econtext)
    6807                 :             : {
    6808                 :             :     ParamListInfo params;
    6809                 :             :     PLpgSQL_execstate *estate;
    6810                 :       98874 :     int         dno = op->d.cparam.paramid - 1;
    6811                 :             :     PLpgSQL_var *var;
    6812                 :             : 
    6813                 :             :     /* fetch back the hook data */
    6814                 :       98874 :     params = econtext->ecxt_param_list_info;
    6815                 :       98874 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6816                 :             :     Assert(dno >= 0 && dno < estate->ndatums);
    6817                 :             : 
    6818                 :             :     /* now we can access the target datum */
    6819                 :       98874 :     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         [ +  + ]:       98874 :     *op->resvalue = MakeExpandedObjectReadOnly(var->value,
    6827                 :             :                                                var->isnull,
    6828                 :             :                                                -1);
    6829                 :       98874 :     *op->resnull = var->isnull;
    6830                 :             : 
    6831                 :             :     /* safety check -- an assertion should be sufficient */
    6832                 :             :     Assert(var->datatype->typoid == op->d.cparam.paramtype);
    6833                 :       98874 : }
    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                 :       44082 : plpgsql_param_eval_recfield(ExprState *state, ExprEvalStep *op,
    6843                 :             :                             ExprContext *econtext)
    6844                 :             : {
    6845                 :             :     ParamListInfo params;
    6846                 :             :     PLpgSQL_execstate *estate;
    6847                 :       44082 :     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                 :       44082 :     params = econtext->ecxt_param_list_info;
    6854                 :       44082 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6855                 :             :     Assert(dno >= 0 && dno < estate->ndatums);
    6856                 :             : 
    6857                 :             :     /* now we can access the target datum */
    6858                 :       44082 :     recfield = (PLpgSQL_recfield *) estate->datums[dno];
    6859                 :             :     Assert(recfield->dtype == PLPGSQL_DTYPE_RECFIELD);
    6860                 :             : 
    6861                 :             :     /* inline the relevant part of exec_eval_datum */
    6862                 :       44082 :     rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
    6863                 :       44082 :     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         [ +  + ]:       44082 :     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         [ +  + ]:       44082 :     if (unlikely(recfield->rectupledescid != erh->er_tupdesc_id))
    6881                 :             :     {
    6882         [ +  + ]:        2604 :         if (!expanded_record_lookup_field(erh,
    6883                 :        2604 :                                           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                 :        2603 :         recfield->rectupledescid = erh->er_tupdesc_id;
    6890                 :             :     }
    6891                 :             : 
    6892                 :             :     /* OK to fetch the field value. */
    6893                 :       44081 :     *op->resvalue = expanded_record_get_field(erh,
    6894                 :             :                                               recfield->finfo.fnumber,
    6895                 :             :                                               op->resnull);
    6896                 :             : 
    6897                 :             :     /* safety check -- needed for, eg, record fields */
    6898         [ +  + ]:       44081 :     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                 :       44079 : }
    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                 :        2111 : plpgsql_param_eval_generic(ExprState *state, ExprEvalStep *op,
    6915                 :             :                            ExprContext *econtext)
    6916                 :             : {
    6917                 :             :     ParamListInfo params;
    6918                 :             :     PLpgSQL_execstate *estate;
    6919                 :        2111 :     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                 :        2111 :     params = econtext->ecxt_param_list_info;
    6926                 :        2111 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6927                 :             :     Assert(dno >= 0 && dno < estate->ndatums);
    6928                 :             : 
    6929                 :             :     /* now we can access the target datum */
    6930                 :        2111 :     datum = estate->datums[dno];
    6931                 :             : 
    6932                 :             :     /* fetch datum's value */
    6933                 :        2111 :     exec_eval_datum(estate, datum,
    6934                 :             :                     &datumtype, &datumtypmod,
    6935                 :             :                     op->resvalue, op->resnull);
    6936                 :             : 
    6937                 :             :     /* safety check -- needed for, eg, record fields */
    6938         [ -  + ]:        2111 :     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                 :        2111 : }
    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                 :       18026 : plpgsql_param_eval_generic_ro(ExprState *state, ExprEvalStep *op,
    6955                 :             :                               ExprContext *econtext)
    6956                 :             : {
    6957                 :             :     ParamListInfo params;
    6958                 :             :     PLpgSQL_execstate *estate;
    6959                 :       18026 :     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                 :       18026 :     params = econtext->ecxt_param_list_info;
    6966                 :       18026 :     estate = (PLpgSQL_execstate *) params->paramFetchArg;
    6967                 :             :     Assert(dno >= 0 && dno < estate->ndatums);
    6968                 :             : 
    6969                 :             :     /* now we can access the target datum */
    6970                 :       18026 :     datum = estate->datums[dno];
    6971                 :             : 
    6972                 :             :     /* fetch datum's value */
    6973                 :       18026 :     exec_eval_datum(estate, datum,
    6974                 :             :                     &datumtype, &datumtypmod,
    6975                 :             :                     op->resvalue, op->resnull);
    6976                 :             : 
    6977                 :             :     /* safety check -- needed for, eg, record fields */
    6978         [ -  + ]:       18026 :     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         [ +  + ]:       18026 :     *op->resvalue = MakeExpandedObjectReadOnly(*op->resvalue,
    6988                 :             :                                                *op->resnull,
    6989                 :             :                                                -1);
    6990                 :       18026 : }
    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                 :       46875 : exec_move_row(PLpgSQL_execstate *estate,
    7005                 :             :               PLpgSQL_variable *target,
    7006                 :             :               HeapTuple tup, TupleDesc tupdesc)
    7007                 :             : {
    7008                 :       46875 :     ExpandedRecordHeader *newerh = NULL;
    7009                 :             : 
    7010                 :             :     /*
    7011                 :             :      * If target is RECORD, we may be able to avoid field-by-field processing.
    7012                 :             :      */
    7013         [ +  + ]:       46875 :     if (target->dtype == PLPGSQL_DTYPE_REC)
    7014                 :             :     {
    7015                 :        7027 :         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         [ +  + ]:        7027 :         if (tupdesc == NULL)
    7024                 :             :         {
    7025         [ +  - ]:        3228 :             if (rec->datatype &&
    7026         [ +  + ]:        3228 :                 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         [ +  + ]:        3211 :                 if (rec->erh)
    7043                 :          81 :                     DeleteExpandedObject(ExpandedRecordGetDatum(rec->erh));
    7044                 :        3211 :                 rec->erh = NULL;
    7045                 :             :             }
    7046                 :        3224 :             return;
    7047                 :             :         }
    7048                 :             : 
    7049                 :             :         /*
    7050                 :             :          * Build a new expanded record with appropriate tupdesc.
    7051                 :             :          */
    7052                 :        3799 :         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         [ +  + ]:        3799 :         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         [ +  + ]:        3746 :             if (!HeapTupleIsValid(tup))
    7071                 :             :             {
    7072                 :             :                 /* No data, so force the record into all-nulls state */
    7073                 :        1085 :                 deconstruct_expanded_record(newerh);
    7074                 :             :             }
    7075                 :             :             else
    7076                 :             :             {
    7077                 :             :                 /* No coercion is needed, so just assign the row value */
    7078                 :        2661 :                 expanded_record_set_tuple(newerh, tup, true, !estate->atomic);
    7079                 :             :             }
    7080                 :             : 
    7081                 :             :             /* Complete the assignment */
    7082                 :        3743 :             assign_record_var(estate, rec, newerh);
    7083                 :             : 
    7084                 :        3743 :             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   [ +  -  +  + ]:       39901 :     if (tupdesc && HeapTupleIsValid(tup))
    7093                 :       39755 :     {
    7094                 :       39776 :         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         [ +  - ]:       39776 :         if (td_natts <= lengthof(values_local))
    7106                 :             :         {
    7107                 :       39776 :             values = values_local;
    7108                 :       39776 :             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                 :       39776 :         heap_deform_tuple(tup, tupdesc, values, nulls);
    7121                 :             : 
    7122                 :       39776 :         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                 :        3977 : make_expanded_record_for_rec(PLpgSQL_execstate *estate,
    7220                 :             :                              PLpgSQL_rec *rec,
    7221                 :             :                              TupleDesc srctupdesc,
    7222                 :             :                              ExpandedRecordHeader *srcerh)
    7223                 :             : {
    7224                 :             :     ExpandedRecordHeader *newerh;
    7225                 :        3977 :     MemoryContext mcontext = get_eval_mcontext(estate);
    7226                 :             : 
    7227         [ +  + ]:        3977 :     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   [ +  +  +  - ]:        3820 :         if (srcerh && !ExpandedRecordIsDomain(srcerh))
    7253                 :         149 :             newerh = make_expanded_record_from_exprecord(srcerh,
    7254                 :             :                                                          mcontext);
    7255                 :             :         else
    7256                 :             :         {
    7257         [ -  + ]:        3671 :             if (!srctupdesc)
    7258                 :           0 :                 srctupdesc = expanded_record_get_tupdesc(srcerh);
    7259                 :        3671 :             newerh = make_expanded_record_from_tupdesc(srctupdesc,
    7260                 :             :                                                        mcontext);
    7261                 :             :         }
    7262                 :             :     }
    7263                 :             : 
    7264                 :        3977 :     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                 :       39911 : 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         [ +  + ]:       39911 :     int         td_natts = tupdesc ? tupdesc->natts : 0;
    7289                 :             :     int         fnum;
    7290                 :             :     int         anum;
    7291                 :       39911 :     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         [ +  + ]:       39911 :     if (tupdesc != NULL)
    7298                 :             :     {
    7299         [ +  + ]:       39786 :         if (plpgsql_extra_errors & PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT)
    7300                 :          24 :             strict_multiassignment_level = ERROR;
    7301         [ +  + ]:       39762 :         else if (plpgsql_extra_warnings & PLPGSQL_XCHECK_STRICTMULTIASSIGNMENT)
    7302                 :          12 :             strict_multiassignment_level = WARNING;
    7303                 :             :     }
    7304                 :             : 
    7305                 :             :     /* Handle RECORD-target case */
    7306         [ +  + ]:       39911 :     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         [ +  - ]:       39848 :     if (target->dtype == PLPGSQL_DTYPE_ROW)
    7463                 :             :     {
    7464                 :       39848 :         PLpgSQL_row *row = (PLpgSQL_row *) target;
    7465                 :             : 
    7466                 :       39848 :         anum = 0;
    7467         [ +  + ]:       83060 :         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                 :       43216 :             var = (PLpgSQL_var *) (estate->datums[row->varnos[fnum]]);
    7476                 :             : 
    7477         [ +  + ]:       43216 :             while (anum < td_natts &&
    7478         [ -  + ]:       43079 :                    TupleDescAttr(tupdesc, anum)->attisdropped)
    7479                 :           0 :                 anum++;         /* skip dropped column in tuple */
    7480                 :             : 
    7481         [ +  + ]:       43216 :             if (anum < td_natts)
    7482                 :             :             {
    7483                 :       43079 :                 value = values[anum];
    7484                 :       43079 :                 isnull = nulls[anum];
    7485                 :       43079 :                 valtype = TupleDescAttr(tupdesc, anum)->atttypid;
    7486                 :       43079 :                 valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
    7487                 :       43079 :                 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                 :       43212 :             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   [ +  +  +  + ]:       39844 :         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                 :       39840 :         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                 :        3354 : make_tuple_from_row(PLpgSQL_execstate *estate,
    7593                 :             :                     PLpgSQL_row *row,
    7594                 :             :                     TupleDesc tupdesc)
    7595                 :             : {
    7596                 :        3354 :     int         natts = tupdesc->natts;
    7597                 :             :     HeapTuple   tuple;
    7598                 :             :     Datum      *dvalues;
    7599                 :             :     bool       *nulls;
    7600                 :             :     int         i;
    7601                 :             : 
    7602         [ -  + ]:        3354 :     if (natts != row->nfields)
    7603                 :           0 :         return NULL;
    7604                 :             : 
    7605                 :        3354 :     dvalues = (Datum *) eval_mcontext_alloc0(estate, natts * sizeof(Datum));
    7606                 :        3354 :     nulls = (bool *) eval_mcontext_alloc(estate, natts * sizeof(bool));
    7607                 :             : 
    7608         [ +  + ]:       13222 :     for (i = 0; i < natts; i++)
    7609                 :             :     {
    7610                 :             :         Oid         fieldtypeid;
    7611                 :             :         int32       fieldtypmod;
    7612                 :             : 
    7613         [ -  + ]:        9868 :         if (TupleDescAttr(tupdesc, i)->attisdropped)
    7614                 :             :         {
    7615                 :           0 :             nulls[i] = true;    /* leave the column as null */
    7616                 :           0 :             continue;
    7617                 :             :         }
    7618                 :             : 
    7619                 :        9868 :         exec_eval_datum(estate, estate->datums[row->varnos[i]],
    7620                 :             :                         &fieldtypeid, &fieldtypmod,
    7621                 :        9868 :                         &dvalues[i], &nulls[i]);
    7622         [ -  + ]:        9868 :         if (fieldtypeid != TupleDescAttr(tupdesc, i)->atttypid)
    7623                 :           0 :             return NULL;
    7624                 :             :         /* XXX should we insist on typmod match, too? */
    7625                 :             :     }
    7626                 :             : 
    7627                 :        3354 :     tuple = heap_form_tuple(tupdesc, dvalues, nulls);
    7628                 :             : 
    7629                 :        3354 :     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                 :        3600 : 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                 :        3600 :     td = DatumGetHeapTupleHeader(value);
    7655                 :             : 
    7656                 :             :     /* Build a temporary HeapTuple control structure */
    7657                 :        3600 :     tmptup->t_len = HeapTupleHeaderGetDatumLength(td);
    7658                 :        3600 :     ItemPointerSetInvalid(&(tmptup->t_self));
    7659                 :        3600 :     tmptup->t_tableOid = InvalidOid;
    7660                 :        3600 :     tmptup->t_data = td;
    7661                 :             : 
    7662                 :             :     /* Extract rowtype info and find a tupdesc */
    7663                 :        3600 :     tupType = HeapTupleHeaderGetTypeId(td);
    7664                 :        3600 :     tupTypmod = HeapTupleHeaderGetTypMod(td);
    7665                 :        3600 :     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                 :        1409 : 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         [ +  + ]:        1409 :     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                 :        1243 :         oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    7826                 :             :         /* Get tuple body (note this could involve detoasting) */
    7827                 :        1243 :         td = DatumGetHeapTupleHeader(value);
    7828                 :        1243 :         MemoryContextSwitchTo(oldcontext);
    7829                 :             : 
    7830                 :             :         /* Build a temporary HeapTuple control structure */
    7831                 :        1243 :         tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
    7832                 :        1243 :         ItemPointerSetInvalid(&(tmptup.t_self));
    7833                 :        1243 :         tmptup.t_tableOid = InvalidOid;
    7834                 :        1243 :         tmptup.t_data = td;
    7835                 :             : 
    7836                 :             :         /* Extract rowtype info */
    7837                 :        1243 :         tupType = HeapTupleHeaderGetTypeId(td);
    7838                 :        1243 :         tupTypmod = HeapTupleHeaderGetTypMod(td);
    7839                 :             : 
    7840                 :             :         /* Now, if the target is record not row, maybe we can optimize ... */
    7841         [ +  + ]:        1243 :         if (target->dtype == PLPGSQL_DTYPE_REC)
    7842                 :             :         {
    7843                 :        1215 :             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         [ +  + ]:        1215 :             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                 :        1165 :                 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   [ +  +  +  + ]:        1127 :             if (rec->rectypeid == RECORDOID || rec->rectypeid == tupType)
    7872                 :             :             {
    7873                 :             :                 ExpandedRecordHeader *newerh;
    7874                 :        1077 :                 MemoryContext mcontext = get_eval_mcontext(estate);
    7875                 :             : 
    7876                 :        1077 :                 newerh = make_expanded_record_from_typeid(tupType, tupTypmod,
    7877                 :             :                                                           mcontext);
    7878                 :        1077 :                 expanded_record_set_tuple(newerh, &tmptup,
    7879                 :        1077 :                                           true, !estate->atomic);
    7880                 :        1077 :                 assign_record_var(estate, rec, newerh);
    7881                 :        1077 :                 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                 :       49429 : 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                 :       49429 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    7954                 :       49429 :     getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
    7955                 :       49429 :     result = OidOutputFunctionCall(typoutput, value);
    7956                 :       49429 :     MemoryContextSwitchTo(oldcontext);
    7957                 :             : 
    7958                 :       49429 :     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                 :      249974 : 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   [ +  +  -  + ]:      249974 :     if (valtype != reqtype ||
    7984         [ #  # ]:           0 :         (valtypmod != reqtypmod && reqtypmod != -1))
    7985                 :             :     {
    7986                 :             :         /* We keep the slow path out-of-line. */
    7987                 :        2610 :         value = do_cast_value(estate, value, isnull, valtype, valtypmod,
    7988                 :             :                               reqtype, reqtypmod);
    7989                 :             :     }
    7990                 :             : 
    7991                 :      249934 :     return value;
    7992                 :             : }
    7993                 :             : 
    7994                 :             : /* ----------
    7995                 :             :  * do_cast_value            Slow path for exec_cast_value.
    7996                 :             :  * ----------
    7997                 :             :  */
    7998                 :             : static Datum
    7999                 :        2610 : 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                 :        2610 :     cast_entry = get_cast_hashentry(estate,
    8007                 :             :                                     valtype, valtypmod,
    8008                 :             :                                     reqtype, reqtypmod);
    8009         [ +  - ]:        2610 :     if (cast_entry)
    8010                 :             :     {
    8011                 :        2610 :         ExprContext *econtext = estate->eval_econtext;
    8012                 :             :         MemoryContext oldcontext;
    8013                 :             : 
    8014                 :        2610 :         oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    8015                 :             : 
    8016                 :        2610 :         econtext->caseValue_datum = value;
    8017                 :        2610 :         econtext->caseValue_isNull = *isnull;
    8018                 :             : 
    8019                 :        2610 :         cast_entry->cast_in_use = true;
    8020                 :             : 
    8021                 :        2610 :         value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
    8022                 :             :                              isnull);
    8023                 :             : 
    8024                 :        2570 :         cast_entry->cast_in_use = false;
    8025                 :             : 
    8026                 :        2570 :         MemoryContextSwitchTo(oldcontext);
    8027                 :             :     }
    8028                 :             : 
    8029                 :        2570 :     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                 :        2610 : 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                 :        2610 :     cast_key.srctype = srctype;
    8056                 :        2610 :     cast_key.dsttype = dsttype;
    8057                 :        2610 :     cast_key.srctypmod = srctypmod;
    8058                 :        2610 :     cast_key.dsttypmod = dsttypmod;
    8059                 :        2610 :     cast_entry = (plpgsql_CastHashEntry *) hash_search(estate->cast_hash,
    8060                 :             :                                                        &cast_key,
    8061                 :             :                                                        HASH_ENTER, &found);
    8062         [ +  + ]:        2610 :     if (!found)                 /* initialize if new entry */
    8063                 :             :     {
    8064                 :             :         /* We need a second lookup to see if a cast_expr_hash entry exists */
    8065                 :         254 :         expr_entry = (plpgsql_CastExprHashEntry *) hash_search(cast_expr_hash,
    8066                 :             :                                                                &cast_key,
    8067                 :             :                                                                HASH_ENTER,
    8068                 :             :                                                                &found);
    8069         [ +  + ]:         254 :         if (!found)             /* initialize if new expr entry */
    8070                 :         217 :             expr_entry->cast_cexpr = NULL;
    8071                 :             : 
    8072                 :         254 :         cast_entry->cast_centry = expr_entry;
    8073                 :         254 :         cast_entry->cast_exprstate = NULL;
    8074                 :         254 :         cast_entry->cast_in_use = false;
    8075                 :         254 :         cast_entry->cast_lxid = InvalidLocalTransactionId;
    8076                 :             :     }
    8077                 :             :     else
    8078                 :             :     {
    8079                 :             :         /* Use always-valid link to avoid a second hash lookup */
    8080                 :        2356 :         expr_entry = cast_entry->cast_centry;
    8081                 :             :     }
    8082                 :             : 
    8083         [ +  + ]:        2610 :     if (expr_entry->cast_cexpr == NULL ||
    8084         [ +  + ]:        2393 :         !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         [ +  + ]:         262 :         if (expr_entry->cast_cexpr)
    8098                 :             :         {
    8099                 :          45 :             FreeCachedExpression(expr_entry->cast_cexpr);
    8100                 :          45 :             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                 :         262 :         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                 :         262 :         placeholder = makeNode(CaseTestExpr);
    8115                 :         262 :         placeholder->typeId = srctype;
    8116                 :         262 :         placeholder->typeMod = srctypmod;
    8117                 :         262 :         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   [ +  +  +  + ]:         262 :         if (srctype == UNKNOWNOID || srctype == RECORDOID)
    8135                 :          73 :             cast_expr = NULL;
    8136                 :             :         else
    8137                 :         189 :             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         [ +  + ]:         262 :         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                 :         262 :         cast_cexpr = GetCachedExpression(cast_expr);
    8174                 :         262 :         cast_expr = cast_cexpr->expr;
    8175                 :             : 
    8176                 :             :         /* Detect whether we have a no-op (RelabelType) coercion */
    8177         [ +  + ]:         262 :         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                 :         262 :         expr_entry->cast_cexpr = cast_cexpr;
    8183                 :         262 :         expr_entry->cast_expr = (Expr *) cast_expr;
    8184                 :             : 
    8185                 :             :         /* Be sure to reset the exprstate hashtable entry, too. */
    8186                 :         262 :         cast_entry->cast_exprstate = NULL;
    8187                 :         262 :         cast_entry->cast_in_use = false;
    8188                 :         262 :         cast_entry->cast_lxid = InvalidLocalTransactionId;
    8189                 :             : 
    8190                 :         262 :         MemoryContextSwitchTo(oldcontext);
    8191                 :             :     }
    8192                 :             : 
    8193                 :             :     /* Done if we have determined that this is a no-op cast. */
    8194         [ -  + ]:        2610 :     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                 :        2610 :     curlxid = MyProc->vxid.lxid;
    8210   [ +  +  +  + ]:        2610 :     if (cast_entry->cast_lxid != curlxid || cast_entry->cast_in_use)
    8211                 :             :     {
    8212                 :         510 :         oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
    8213                 :         510 :         cast_entry->cast_exprstate = ExecInitExpr(expr_entry->cast_expr, NULL);
    8214                 :         510 :         cast_entry->cast_in_use = false;
    8215                 :         510 :         cast_entry->cast_lxid = curlxid;
    8216                 :         510 :         MemoryContextSwitchTo(oldcontext);
    8217                 :             :     }
    8218                 :             : 
    8219                 :        2610 :     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                 :       18105 : 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                 :       18105 :     expr->expr_simple_expr = NULL;
    8245                 :       18105 :     expr->expr_rwopt = PLPGSQL_RWOPT_UNKNOWN;
    8246                 :       18105 :     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         [ +  + ]:       18105 :     if (!exec_is_simple_query(expr))
    8255                 :        2439 :         return;
    8256                 :             : 
    8257                 :             :     /* exec_is_simple_query verified that there's just one CachedPlanSource */
    8258                 :       15666 :     plansources = SPI_plan_get_plan_sources(expr->plan);
    8259                 :       15666 :     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                 :       15666 :     oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
    8267                 :       15666 :     cplan = SPI_plan_get_cached_plan(expr->plan);
    8268                 :       15637 :     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         [ +  - ]:       15637 :     if (CachedPlanAllowsSimpleValidityCheck(plansource, cplan,
    8280                 :             :                                             estate->simple_eval_resowner))
    8281                 :             :     {
    8282                 :             :         /* Remember that we have the refcount */
    8283                 :       15637 :         expr->expr_simple_plansource = plansource;
    8284                 :       15637 :         expr->expr_simple_plan = cplan;
    8285                 :       15637 :         expr->expr_simple_plan_lxid = MyProc->vxid.lxid;
    8286                 :             : 
    8287                 :             :         /* Share the remaining work with the replan code path */
    8288                 :       15637 :         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                 :       15637 :     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                 :        1253 :         return false;
    8334         [ +  + ]:       20167 :     if (query->rtable != NIL)
    8335                 :         726 :         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         [ +  - ]:       19441 :     if (query->hasAggs ||
    8344         [ +  - ]:       19441 :         query->hasWindowFuncs ||
    8345         [ +  + ]:       19441 :         query->hasTargetSRFs ||
    8346         [ +  + ]:       19415 :         query->hasSubLinks ||
    8347         [ +  - ]:       19057 :         query->cteList ||
    8348         [ +  - ]:       19057 :         query->jointree->fromlist ||
    8349         [ +  - ]:       19057 :         query->jointree->quals ||
    8350         [ +  - ]:       19057 :         query->groupClause ||
    8351         [ +  - ]:       19057 :         query->groupingSets ||
    8352         [ +  - ]:       19057 :         query->havingQual ||
    8353         [ +  - ]:       19057 :         query->windowClause ||
    8354         [ +  - ]:       19057 :         query->distinctClause ||
    8355         [ +  - ]:       19057 :         query->sortClause ||
    8356         [ +  - ]:       19057 :         query->limitOffset ||
    8357         [ +  - ]:       19057 :         query->limitCount ||
    8358         [ -  + ]:       19057 :         query->setOperations)
    8359                 :         384 :         return false;
    8360                 :             : 
    8361                 :             :     /*
    8362                 :             :      * 4. The query must have a single attribute as result.
    8363                 :             :      */
    8364         [ +  + ]:       19057 :     if (list_length(query->targetList) != 1)
    8365                 :          77 :         return false;
    8366                 :             : 
    8367                 :             :     /*
    8368                 :             :      * OK, we can treat it as a simple plan.
    8369                 :             :      */
    8370                 :       18980 :     return true;
    8371                 :             : }
    8372                 :             : 
    8373                 :             : /*
    8374                 :             :  * exec_save_simple_expr --- extract simple expression from CachedPlan
    8375                 :             :  */
    8376                 :             : static void
    8377                 :       18951 : 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                 :       18951 :     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                 :       18951 :     plan = stmt->planTree;
    8403                 :             :     for (;;)
    8404                 :             :     {
    8405                 :             :         /* Extract the single tlist expression */
    8406                 :           0 :         Assert(list_length(plan->targetlist) == 1);
    8407                 :       18951 :         tle_expr = linitial_node(TargetEntry, plan->targetlist)->expr;
    8408                 :             : 
    8409         [ +  + ]:       18951 :         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                 :       18950 :             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                 :       18951 :     expr->expr_simple_expr = tle_expr;
    8443                 :       18951 :     expr->expr_simple_state = NULL;
    8444                 :       18951 :     expr->expr_simple_in_use = false;
    8445                 :       18951 :     expr->expr_simple_lxid = InvalidLocalTransactionId;
    8446                 :             :     /* Also stash away the expression result type */
    8447                 :       18951 :     expr->expr_simple_type = exprType((Node *) tle_expr);
    8448                 :       18951 :     expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
    8449                 :             :     /* We also want to remember if it is immutable or not */
    8450                 :       18951 :     expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr);
    8451                 :       18951 : }
    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                 :      100895 : exec_set_found(PLpgSQL_execstate *estate, bool state)
    8696                 :             : {
    8697                 :             :     PLpgSQL_var *var;
    8698                 :             : 
    8699                 :      100895 :     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         [ -  + ]:      100895 :     pg_assume(var->datatype->typlen != -1);
    8708                 :             : 
    8709                 :      100895 :     assign_simple_var(estate, var, BoolGetDatum(state), false, false);
    8710                 :      100895 : }
    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                 :       69160 : 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         [ +  + ]:       69160 :     if (estate->simple_eval_estate == NULL)
    8738                 :             :     {
    8739                 :             :         MemoryContext oldcontext;
    8740                 :             : 
    8741         [ +  + ]:       10373 :         if (shared_simple_eval_estate == NULL)
    8742                 :             :         {
    8743                 :       10369 :             oldcontext = MemoryContextSwitchTo(TopTransactionContext);
    8744                 :       10369 :             shared_simple_eval_estate = CreateExecutorState();
    8745                 :       10369 :             MemoryContextSwitchTo(oldcontext);
    8746                 :             :         }
    8747                 :       10373 :         estate->simple_eval_estate = shared_simple_eval_estate;
    8748                 :             :     }
    8749                 :             : 
    8750                 :             :     /*
    8751                 :             :      * Likewise for the simple-expression resource owner.
    8752                 :             :      */
    8753         [ +  + ]:       69160 :     if (estate->simple_eval_resowner == NULL)
    8754                 :             :     {
    8755         [ +  + ]:       10373 :         if (shared_simple_eval_resowner == NULL)
    8756                 :       10369 :             shared_simple_eval_resowner =
    8757                 :       10369 :                 ResourceOwnerCreate(TopTransactionResourceOwner,
    8758                 :             :                                     "PL/pgSQL simple expressions");
    8759                 :       10373 :         estate->simple_eval_resowner = shared_simple_eval_resowner;
    8760                 :             :     }
    8761                 :             : 
    8762                 :             :     /*
    8763                 :             :      * Create a child econtext for the current function.
    8764                 :             :      */
    8765                 :       69160 :     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                 :       69160 :         MemoryContextAlloc(TopTransactionContext,
    8773                 :             :                            sizeof(SimpleEcontextStackEntry));
    8774                 :             : 
    8775                 :       69160 :     entry->stack_econtext = estate->eval_econtext;
    8776                 :       69160 :     entry->xact_subxid = GetCurrentSubTransactionId();
    8777                 :             : 
    8778                 :       69160 :     entry->next = simple_econtext_stack;
    8779                 :       69160 :     simple_econtext_stack = entry;
    8780                 :       69160 : }
    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                 :       56782 : 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                 :       56782 :     next = simple_econtext_stack->next;
    8797                 :       56782 :     pfree(simple_econtext_stack);
    8798                 :       56782 :     simple_econtext_stack = next;
    8799                 :             : 
    8800                 :       56782 :     FreeExprContext(estate->eval_econtext, true);
    8801                 :       56782 :     estate->eval_econtext = NULL;
    8802                 :       56782 : }
    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                 :      209474 : 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   [ +  +  +  + ]:      209474 :     if (event == XACT_EVENT_COMMIT ||
    8824         [ +  + ]:      109610 :         event == XACT_EVENT_PARALLEL_COMMIT ||
    8825                 :             :         event == XACT_EVENT_PREPARE)
    8826                 :             :     {
    8827                 :       99882 :         simple_econtext_stack = NULL;
    8828                 :             : 
    8829         [ +  + ]:       99882 :         if (shared_simple_eval_estate)
    8830                 :        9443 :             FreeExecutorState(shared_simple_eval_estate);
    8831                 :       99882 :         shared_simple_eval_estate = NULL;
    8832         [ +  + ]:       99882 :         if (shared_simple_eval_resowner)
    8833                 :        9443 :             ReleaseAllPlanCacheRefsInOwner(shared_simple_eval_resowner);
    8834                 :       99882 :         shared_simple_eval_resowner = NULL;
    8835                 :             :     }
    8836   [ +  +  +  + ]:      109592 :     else if (event == XACT_EVENT_ABORT ||
    8837                 :             :              event == XACT_EVENT_PARALLEL_ABORT)
    8838                 :             :     {
    8839                 :        9658 :         simple_econtext_stack = NULL;
    8840                 :        9658 :         shared_simple_eval_estate = NULL;
    8841                 :        9658 :         shared_simple_eval_resowner = NULL;
    8842                 :             :     }
    8843                 :      209474 : }
    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                 :       26800 : plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid,
    8854                 :             :                    SubTransactionId parentSubid, void *arg)
    8855                 :             : {
    8856   [ +  +  +  + ]:       26800 :     if (event == SUBXACT_EVENT_COMMIT_SUB || event == SUBXACT_EVENT_ABORT_SUB)
    8857                 :             :     {
    8858         [ +  + ]:       20192 :         while (simple_econtext_stack != NULL &&
    8859         [ +  + ]:       19307 :                simple_econtext_stack->xact_subxid == mySubid)
    8860                 :             :         {
    8861                 :             :             SimpleEcontextStackEntry *next;
    8862                 :             : 
    8863                 :        9759 :             FreeExprContext(simple_econtext_stack->stack_econtext,
    8864                 :             :                             (event == SUBXACT_EVENT_COMMIT_SUB));
    8865                 :        9759 :             next = simple_econtext_stack->next;
    8866                 :        9759 :             pfree(simple_econtext_stack);
    8867                 :        9759 :             simple_econtext_stack = next;
    8868                 :             :         }
    8869                 :             :     }
    8870                 :       26800 : }
    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                 :      330104 : 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   [ +  +  +  +  :      359891 :     if (!estate->atomic && !isnull && var->datatype->typlen == -1 &&
             +  +  +  + ]
    8897                 :       29787 :         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         [ +  + ]:      330104 :     if (var->freeval)
    8922                 :             :     {
    8923   [ +  -  +  +  :       64163 :         if (DatumIsReadWriteExpandedObject(var->value,
                   +  + ]
    8924                 :             :                                            var->isnull,
    8925                 :             :                                            var->datatype->typlen))
    8926                 :        4747 :             DeleteExpandedObject(var->value);
    8927                 :             :         else
    8928                 :       59416 :             pfree(DatumGetPointer(var->value));
    8929                 :             :     }
    8930                 :             :     /* Assign new value to datum */
    8931                 :      330104 :     var->value = newvalue;
    8932                 :      330104 :     var->isnull = isnull;
    8933                 :      330104 :     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                 :      330104 :     var->promise = PLPGSQL_PROMISE_NONE;
    8941                 :      330104 : }
    8942                 :             : 
    8943                 :             : /*
    8944                 :             :  * free old value of a text variable and assign new value from C string
    8945                 :             :  */
    8946                 :             : static void
    8947                 :       15537 : assign_text_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, const char *str)
    8948                 :             : {
    8949                 :       15537 :     assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
    8950                 :       15537 : }
    8951                 :             : 
    8952                 :             : /*
    8953                 :             :  * assign_record_var --- assign a new value to any REC datum.
    8954                 :             :  */
    8955                 :             : static void
    8956                 :        5037 : 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                 :        5037 :     TransferExpandedRecord(erh, estate->datum_context);
    8963                 :             : 
    8964                 :             :     /* Free the old value ... */
    8965         [ +  + ]:        5037 :     if (rec->erh)
    8966                 :        1232 :         DeleteExpandedObject(ExpandedRecordGetDatum(rec->erh));
    8967                 :             : 
    8968                 :             :     /* ... and install the new */
    8969                 :        5037 :     rec->erh = erh;
    8970                 :        5037 : }
    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                 :       17722 : 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         [ +  + ]:       17722 :     if (params == NIL)
    8990                 :       17425 :         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                 :        6402 : 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                 :        6402 :     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                 :        6402 :     query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
    9081         [ -  + ]:        6402 :     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                 :        6402 :     querystr = convert_value_to_string(estate, query, restype);
    9088                 :             : 
    9089                 :             :     /* copy it into the stmt_mcontext before we clean up */
    9090                 :        6402 :     querystr = MemoryContextStrdup(stmt_mcontext, querystr);
    9091                 :             : 
    9092                 :        6402 :     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                 :        6402 :     memset(&options, 0, sizeof(options));
    9100                 :        6402 :     options.params = exec_eval_using_params(estate, params);
    9101                 :        6402 :     options.cursorOptions = cursorOptions;
    9102                 :        6402 :     options.read_only = estate->readonly_func;
    9103                 :             : 
    9104                 :        6402 :     portal = SPI_cursor_parse_open(portalname, querystr, &options);
    9105                 :             : 
    9106         [ -  + ]:        6402 :     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                 :        6402 :     MemoryContextReset(stmt_mcontext);
    9112                 :             : 
    9113                 :        6402 :     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