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 % 2756 2509
Test Date: 2026-10-29 00:16:02 Functions: 100.0 % 99 99
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 68.2 % 1922 1311

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

Generated by: LCOV version 2.0-1