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 : : ¶misnull,
3843 : : ¶mtypeid,
3844 : : ¶mtypmod);
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 = ¶mLI->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(¶mstr);
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 : : ¶mtypeid, ¶mtypmod,
9172 : : ¶mdatum, ¶misnull);
9173 : :
9174 [ + + ]: 32 : appendStringInfo(¶mstr, "%s%s = ",
9175 : : paramno > 0 ? ", " : "",
9176 : : curvar->refname);
9177 : :
9178 [ - + ]: 32 : if (paramisnull)
9179 : 0 : appendStringInfoString(¶mstr, "NULL");
9180 : : else
9181 : 32 : appendStringInfoStringQuoted(¶mstr,
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(¶mstr);
9214 [ + + ]: 20 : for (paramno = 0; paramno < paramLI->numParams; paramno++)
9215 : : {
9216 : 12 : ParamExternData *prm = ¶mLI->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(¶mstr, "%s$%d = ",
9224 : : paramno > 0 ? ", " : "",
9225 : : paramno + 1);
9226 : :
9227 [ - + ]: 12 : if (prm->isnull)
9228 : 0 : appendStringInfoString(¶mstr, "NULL");
9229 : : else
9230 : 12 : appendStringInfoStringQuoted(¶mstr,
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 : : }
|