1 /*-------------------------------------------------------------------------
2  *
3  * stmtwalk.c
4  *
5  *			  iteration over plpgsql statements loop
6  *
7  * by Pavel Stehule 2013-2021
8  *
9  *-------------------------------------------------------------------------
10  */
11 
12 #include "plpgsql_check.h"
13 
14 #include "access/tupconvert.h"
15 #include "catalog/pg_collation.h"
16 #include "catalog/pg_type.h"
17 #include "nodes/nodeFuncs.h"
18 #include "nodes/value.h"
19 #include "parser/parse_node.h"
20 #include "parser/parser.h"
21 #include "common/keywords.h"
22 
23 static void check_stmts(PLpgSQL_checkstate *cstate, List *stmts, int *closing, List **exceptions);
24 static PLpgSQL_stmt_stack_item * push_stmt_to_stmt_stack(PLpgSQL_checkstate *cstate);
25 static void pop_stmt_from_stmt_stack(PLpgSQL_checkstate *cstate);
26 static bool is_any_loop_stmt(PLpgSQL_stmt *stmt);
27 static PLpgSQL_stmt * find_nearest_loop(PLpgSQL_stmt_stack_item *current);
28 static PLpgSQL_stmt * find_stmt_with_label(char *label, PLpgSQL_stmt_stack_item *current);
29 static int possibly_closed(int c);
30 static int merge_closing(int c, int c_local, List **exceptions, List *exceptions_local, int err_code);
31 static bool exception_matches_conditions(int sqlerrstate, PLpgSQL_condition *cond);
32 static bool found_shadowed_variable(char *varname, PLpgSQL_stmt_stack_item *current, PLpgSQL_checkstate *cstate);
33 
34 #if PG_VERSION_NUM >= 110000
35 
36 static void check_dynamic_sql(PLpgSQL_checkstate *cstate, PLpgSQL_stmt *stmt, PLpgSQL_expr *query, bool into, PLpgSQL_variable *target, List *params);
37 
38 #else
39 
40 static void check_dynamic_sql(PLpgSQL_checkstate *cstate, PLpgSQL_stmt *stmt, PLpgSQL_expr *query, bool into, PLpgSQL_row *row, PLpgSQL_rec *rec, List *params);
41 
42 #endif
43 
44 #if PG_VERSION_NUM >= 110000
45 
46 static void
check_variable(PLpgSQL_checkstate * cstate,PLpgSQL_variable * var)47 check_variable(PLpgSQL_checkstate *cstate, PLpgSQL_variable *var)
48 {
49 	/* leave quickly when var is not defined */
50 	if (var == NULL)
51 		return;
52 
53 	if (var->dtype == PLPGSQL_DTYPE_ROW)
54 	{
55 		PLpgSQL_row *row = (PLpgSQL_row *) var;
56 		int		fnum;
57 
58 		for (fnum = 0; fnum < row->nfields; fnum++)
59 		{
60 			/* skip dropped columns */
61 			if (row->varnos[fnum] < 0)
62 				continue;
63 
64 			plpgsql_check_target(cstate, row->varnos[fnum], NULL, NULL);
65 		}
66 		plpgsql_check_record_variable_usage(cstate, row->dno, true);
67 
68 		return;
69 	}
70 
71 	if (var->dtype == PLPGSQL_DTYPE_REC)
72 	{
73 		PLpgSQL_rec *rec = (PLpgSQL_rec *) var;
74 
75 		/*
76 		 * There are no checks done on records currently; just record that the
77 		 * variable is not unused.
78 		 */
79 		plpgsql_check_record_variable_usage(cstate, rec->dno, true);
80 
81 		return;
82 	}
83 
84 	elog(ERROR, "unsupported dtype %d", var->dtype);
85 }
86 
87 #endif
88 
89 bool
plpgsql_check_is_reserved_keyword(char * name)90 plpgsql_check_is_reserved_keyword(char *name)
91 {
92 	int		i;
93 
94 #if PG_VERSION_NUM < 120000
95 
96 	for (i = 0; i < NumScanKeywords; i++)
97 	{
98 		if (ScanKeywords[i].category == RESERVED_KEYWORD &&
99 				strcmp(name, ScanKeywords[i].name) == 0)
100 			return true;
101 	}
102 
103 #else
104 
105 	for (i = 0; i < ScanKeywords.num_keywords; i++)
106 	{
107 		if (ScanKeywordCategories[i] == RESERVED_KEYWORD)
108 		{
109 			char	   *value;
110 
111 			value = unconstify(char *, GetScanKeyword(i, &ScanKeywords));
112 			if (strcmp(name, value) == 0)
113 				return true;
114 		}
115 	}
116 
117 #endif
118 
119 	return false;
120 }
121 
122 /*
123  * walk over all plpgsql statements - search and check expressions
124  *
125  */
126 void
plpgsql_check_stmt(PLpgSQL_checkstate * cstate,PLpgSQL_stmt * stmt,int * closing,List ** exceptions)127 plpgsql_check_stmt(PLpgSQL_checkstate *cstate, PLpgSQL_stmt *stmt, int *closing, List **exceptions)
128 {
129 	TupleDesc	tupdesc = NULL;
130 	PLpgSQL_function *func;
131 	ResourceOwner oldowner;
132 	MemoryContext oldCxt = CurrentMemoryContext;
133 	PLpgSQL_stmt_stack_item *outer_stmt;
134 	plpgsql_check_pragma_vector pragma_vector;
135 
136 	if (stmt == NULL)
137 		return;
138 
139 	if (cstate->stop_check)
140 		return;
141 
142 	cstate->estate->err_stmt = stmt;
143 	cstate->was_pragma = false;
144 
145 	func = cstate->estate->func;
146 	pragma_vector = cstate->pragma_vector;
147 
148 	/*
149 	 * Attention - returns NULL, when there are not any outer level
150 	 */
151 	outer_stmt = push_stmt_to_stmt_stack(cstate);
152 
153 	oldowner = CurrentResourceOwner;
154 	BeginInternalSubTransaction(NULL);
155 	MemoryContextSwitchTo(oldCxt);
156 
157 	PG_TRY();
158 	{
159 		switch (PLPGSQL_STMT_TYPES stmt->cmd_type)
160 		{
161 			case PLPGSQL_STMT_BLOCK:
162 				{
163 					PLpgSQL_stmt_block *stmt_block = (PLpgSQL_stmt_block *) stmt;
164 					int			i;
165 					PLpgSQL_datum *d;
166 
167 					for (i = 0; i < stmt_block->n_initvars; i++)
168 					{
169 						char	   *refname;
170 
171 						d = func->datums[stmt_block->initvarnos[i]];
172 
173 						if (d->dtype == PLPGSQL_DTYPE_VAR ||
174 							d->dtype == PLPGSQL_DTYPE_ROW ||
175 							d->dtype == PLPGSQL_DTYPE_REC)
176 						{
177 							PLpgSQL_variable *var = (PLpgSQL_variable *) d;
178 							StringInfoData str;
179 
180 							initStringInfo(&str);
181 							appendStringInfo(&str, "during statement block local variable \"%s\" initialization on line %d",
182 												 var->refname,
183 												 var->lineno);
184 
185 							cstate->estate->err_text = str.data;
186 
187 #if PG_VERSION_NUM >= 110000
188 
189 							if (var->default_val)
190 								plpgsql_check_assignment(cstate,
191 														 var->default_val,
192 														 NULL,
193 														 NULL,
194 														 var->dno);
195 
196 #else
197 
198 							if (d->dtype == PLPGSQL_DTYPE_VAR &&
199 									((PLpgSQL_var *) var)->default_val)
200 								plpgsql_check_assignment(cstate,
201 														 ((PLpgSQL_var *) var)->default_val,
202 														 NULL,
203 														 NULL,
204 														 var->dno);
205 
206 
207 #endif
208 
209 							cstate->estate->err_text = NULL;
210 							pfree(str.data);
211 						}
212 
213 						refname = plpgsql_check_datum_get_refname(d);
214 						if (refname != NULL)
215 						{
216 							ListCell   *l;
217 
218 							if (plpgsql_check_is_reserved_keyword(refname))
219 							{
220 								StringInfoData str;
221 
222 								initStringInfo(&str);
223 								appendStringInfo(&str, "name of variable \"%s\" is reserved keyword",
224 												 refname);
225 
226 								plpgsql_check_put_error(cstate,
227 											  0, 0,
228 											  str.data,
229 											  "The reserved keyword was used as variable name.",
230 											  NULL,
231 											  PLPGSQL_CHECK_WARNING_OTHERS,
232 											  0, NULL, NULL);
233 								pfree(str.data);
234 							}
235 
236 							foreach(l, cstate->argnames)
237 							{
238 								char	   *argname = (char *) lfirst(l);
239 
240 								if (strcmp(argname, refname) == 0)
241 								{
242 									StringInfoData str;
243 
244 									initStringInfo(&str);
245 									appendStringInfo(&str, "parameter \"%s\" is overlapped",
246 													 refname);
247 
248 									plpgsql_check_put_error(cstate,
249 												  0, 0,
250 												  str.data,
251 												  "Local variable overlap function parameter.",
252 												  NULL,
253 												  PLPGSQL_CHECK_WARNING_OTHERS,
254 												  0, NULL, NULL);
255 									pfree(str.data);
256 								}
257 							}
258 
259 							if (found_shadowed_variable(refname, outer_stmt, cstate))
260 							{
261 								StringInfoData str;
262 
263 								initStringInfo(&str);
264 								appendStringInfo(&str, "variable \"%s\" shadows a previously defined variable",
265 													 refname);
266 
267 								plpgsql_check_put_error(cstate,
268 												  0, 0,
269 												  str.data,
270 												  NULL,
271 												  "SET plpgsql.extra_warnings TO 'shadowed_variables'",
272 												  PLPGSQL_CHECK_WARNING_EXTRA,
273 												  0, NULL, NULL);
274 								pfree(str.data);
275 							}
276 						}
277 					}
278 
279 					check_stmts(cstate, stmt_block->body, closing, exceptions);
280 
281 					if (stmt_block->exceptions)
282 					{
283 						int closing_local;
284 						List   *exceptions_local = NIL;
285 						int		closing_handlers = PLPGSQL_CHECK_UNKNOWN;
286 						List   *exceptions_transformed = NIL;
287 
288 						if (*closing == PLPGSQL_CHECK_CLOSED_BY_EXCEPTIONS)
289 						{
290 							ListCell   *lc;
291 							ListCell   *l;
292 							int		errn = 0;
293 							int    *err_codes = NULL;
294 							int		nerr_codes = 0;
295 
296 							/* copy errcodes to a array */
297 							nerr_codes = list_length(*exceptions);
298 							err_codes = palloc(sizeof(int) * nerr_codes);
299 
300 							foreach(lc, *exceptions)
301 							{
302 								err_codes[errn++] = lfirst_int(lc);
303 							}
304 
305 							foreach(l, stmt_block->exceptions->exc_list)
306 							{
307 								PLpgSQL_exception *exception = (PLpgSQL_exception *) lfirst(l);
308 
309 								/* RETURN in exception handler ~ is possible closing */
310 								check_stmts(cstate, exception->action,
311 												&closing_local, &exceptions_local);
312 
313 								if (*exceptions != NIL)
314 								{
315 									int		idx;
316 
317 									for (idx = 0; idx < nerr_codes; idx++)
318 									{
319 										int		err_code = err_codes[idx];
320 
321 										if (err_code != -1 &&
322 											exception_matches_conditions(err_code, exception->conditions))
323 										{
324 											closing_handlers = merge_closing(closing_handlers, closing_local,
325 																			 &exceptions_transformed, exceptions_local,
326 																			 err_code);
327 											*exceptions = list_delete_int(*exceptions, err_code);
328 											err_codes[idx] = -1;
329 										}
330 									}
331 								}
332 							}
333 
334 							Assert(err_codes != NULL);
335 							pfree(err_codes);
336 
337 							if (closing_handlers != PLPGSQL_CHECK_UNKNOWN)
338 							{
339 								*closing = closing_handlers;
340 								if (closing_handlers == PLPGSQL_CHECK_CLOSED_BY_EXCEPTIONS)
341 									*exceptions = list_concat_unique_int(*exceptions, exceptions_transformed);
342 								else
343 									*exceptions = NIL;
344 							}
345 						}
346 						else
347 						{
348 							ListCell   *l;
349 
350 							closing_handlers = *closing;
351 
352 							foreach(l, stmt_block->exceptions->exc_list)
353 							{
354 								PLpgSQL_exception *exception = (PLpgSQL_exception *) lfirst(l);
355 
356 								/* RETURN in exception handler ~ it is possible closing only */
357 								check_stmts(cstate, exception->action,
358 												&closing_local, &exceptions_local);
359 
360 								closing_handlers = merge_closing(closing_handlers, closing_local,
361 																 &exceptions_transformed, exceptions_local,
362 																 -1);
363 							}
364 
365 							*closing = closing_handlers;
366 
367 							if (closing_handlers == PLPGSQL_CHECK_CLOSED_BY_EXCEPTIONS)
368 								*exceptions = exceptions_transformed;
369 							else
370 								*exceptions = NIL;
371 						}
372 
373 						/*
374 						 * Mark the hidden variables SQLSTATE and SQLERRM used
375 						 * even if they actually weren't.  Not using them
376 						 * should practically never be a sign of a problem, so
377 						 * there's no point in annoying the user.
378 						 */
379 						plpgsql_check_record_variable_usage(cstate, stmt_block->exceptions->sqlstate_varno, false);
380 						plpgsql_check_record_variable_usage(cstate, stmt_block->exceptions->sqlerrm_varno, false);
381 					}
382 				}
383 				break;
384 
385 			case PLPGSQL_STMT_ASSERT:
386 				{
387 					PLpgSQL_stmt_assert *stmt_assert = (PLpgSQL_stmt_assert *) stmt;
388 
389 					/*
390 					 * Should or should not to depends on plpgsql_check_asserts?
391 					 * I am thinking, so any code (active or inactive) should be valid,
392 					 * so I ignore plpgsql_check_asserts option.
393 					 */
394 					plpgsql_check_expr_with_scalar_type(cstate,
395 									 stmt_assert->cond, BOOLOID, true);
396 					if (stmt_assert->message != NULL)
397 						plpgsql_check_expr(cstate, stmt_assert->message);
398 				}
399 				break;
400 
401 			case PLPGSQL_STMT_ASSIGN:
402 				{
403 					PLpgSQL_stmt_assign *stmt_assign = (PLpgSQL_stmt_assign *) stmt;
404 					PLpgSQL_datum *d = (PLpgSQL_datum *) cstate->estate->datums[stmt_assign->varno];
405 					StringInfoData str;
406 
407 					initStringInfo(&str);
408 
409 					if (d->dtype == PLPGSQL_DTYPE_VAR ||
410 						d->dtype == PLPGSQL_DTYPE_ROW ||
411 						d->dtype == PLPGSQL_DTYPE_REC)
412 					{
413 						PLpgSQL_variable *var = (PLpgSQL_variable *) d;
414 
415 						appendStringInfo(&str, "at assignment to variable \"%s\" declared on line %d",
416 										 var->refname,
417 										 var->lineno);
418 
419 						cstate->estate->err_text = str.data;
420 					}
421 					else if (d->dtype == PLPGSQL_DTYPE_RECFIELD)
422 					{
423 						PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) d;
424 						PLpgSQL_variable *var = (PLpgSQL_variable *) cstate->estate->datums[recfield->recparentno];
425 
426 						appendStringInfo(&str, "at assignment to field \"%s\" of variable \"%s\" declared on line %d",
427 										 recfield->fieldname,
428 										 var->refname,
429 										 var->lineno);
430 
431 						cstate->estate->err_text = str.data;
432 					}
433 
434 #if PG_VERSION_NUM < 140000
435 
436 					else if (d->dtype == PLPGSQL_DTYPE_ARRAYELEM)
437 					{
438 						PLpgSQL_arrayelem *elem = (PLpgSQL_arrayelem *) d;
439 						PLpgSQL_variable *var = (PLpgSQL_variable *) cstate->estate->datums[elem->arrayparentno];
440 
441 						appendStringInfo(&str, "at assignment to element of variable \"%s\" declared on line %d",
442 										 var->refname,
443 										 var->lineno);
444 
445 						cstate->estate->err_text = str.data;
446 					}
447 
448 #endif
449 
450 					plpgsql_check_assignment(cstate, stmt_assign->expr, NULL, NULL,
451 											 stmt_assign->varno);
452 
453 					pfree(str.data);
454 					cstate->estate->err_text = NULL;
455 				}
456 				break;
457 
458 			case PLPGSQL_STMT_IF:
459 				{
460 					PLpgSQL_stmt_if	*stmt_if = (PLpgSQL_stmt_if *) stmt;
461 					ListCell    *l;
462 					int		closing_local;
463 					int		closing_all_paths = PLPGSQL_CHECK_UNKNOWN;
464 					List   *exceptions_local;
465 
466 					plpgsql_check_expr_with_scalar_type(cstate,
467 									     stmt_if->cond, BOOLOID, true);
468 
469 					check_stmts(cstate, stmt_if->then_body, &closing_local,
470 								&exceptions_local);
471 					closing_all_paths = merge_closing(closing_all_paths,
472 													  closing_local,
473 													  exceptions,
474 													  exceptions_local,
475 													  -1);
476 
477 					foreach(l, stmt_if->elsif_list)
478 					{
479 						PLpgSQL_if_elsif *elif = (PLpgSQL_if_elsif *) lfirst(l);
480 
481 						plpgsql_check_expr_with_scalar_type(cstate,
482 										     elif->cond, BOOLOID, true);
483 						check_stmts(cstate, elif->stmts, &closing_local,
484 									&exceptions_local);
485 						closing_all_paths = merge_closing(closing_all_paths,
486 														  closing_local,
487 														  exceptions,
488 														  exceptions_local,
489 														  -1);
490 					}
491 
492 					check_stmts(cstate, stmt_if->else_body, &closing_local,
493 								&exceptions_local);
494 					closing_all_paths = merge_closing(closing_all_paths,
495 													  closing_local,
496 													  exceptions,
497 													  exceptions_local,
498 													  -1);
499 
500 					if (stmt_if->else_body != NULL)
501 						*closing = closing_all_paths;
502 					else if (closing_all_paths == PLPGSQL_CHECK_UNCLOSED)
503 						*closing = PLPGSQL_CHECK_UNCLOSED;
504 					else
505 						*closing = PLPGSQL_CHECK_POSSIBLY_CLOSED;
506 				}
507 				break;
508 
509 			case PLPGSQL_STMT_CASE:
510 				{
511 					PLpgSQL_stmt_case *stmt_case = (PLpgSQL_stmt_case *) stmt;
512 					Oid			result_oid;
513 					int			closing_local;
514 					List	    *exceptions_local;
515 					ListCell    *l;
516 					int		closing_all_paths = PLPGSQL_CHECK_UNKNOWN;
517 
518 					if (stmt_case->t_expr != NULL)
519 					{
520 						PLpgSQL_var *t_var = (PLpgSQL_var *) cstate->estate->datums[stmt_case->t_varno];
521 
522 						/*
523 						 * we need to set hidden variable type
524 						 */
525 						plpgsql_check_expr_generic(cstate, stmt_case->t_expr);
526 
527 						/* record all variables used by the query */
528 						cstate->used_variables = bms_add_members(cstate->used_variables,
529 																 stmt_case->t_expr->paramnos);
530 
531 						tupdesc = plpgsql_check_expr_get_desc(cstate,
532 												stmt_case->t_expr,
533 												false,	/* no element type */
534 												true,	/* expand record */
535 												true,	/* is expression */
536 												NULL);
537 						result_oid = TupleDescAttr(tupdesc, 0)->atttypid;
538 
539 						/*
540 						 * When expected datatype is different from real,
541 						 * change it. Note that what we're modifying here is
542 						 * an execution copy of the datum, so this doesn't
543 						 * affect the originally stored function parse tree.
544 						 */
545 						if (t_var->datatype->typoid != result_oid)
546 
547 #ifdef PLPGSQL_BUILD_DATATYPE_4
548 
549 							t_var->datatype = plpgsql_check__build_datatype_p(result_oid,
550 																	 -1,
551 								   cstate->estate->func->fn_input_collation,
552 								   t_var->datatype->origtypname);
553 
554 #else
555 
556 							t_var->datatype = plpgsql_check__build_datatype_p(result_oid,
557 																	 -1,
558 								   cstate->estate->func->fn_input_collation);
559 
560 #endif
561 
562 						ReleaseTupleDesc(tupdesc);
563 					}
564 
565 					foreach(l, stmt_case->case_when_list)
566 					{
567 						PLpgSQL_case_when *cwt = (PLpgSQL_case_when *) lfirst(l);
568 
569 						plpgsql_check_expr(cstate, cwt->expr);
570 						check_stmts(cstate, cwt->stmts, &closing_local, &exceptions_local);
571 						closing_all_paths = merge_closing(closing_all_paths,
572 														  closing_local,
573 														  exceptions,
574 														  exceptions_local,
575 														  -1);
576 					}
577 
578 					if (stmt_case->else_stmts)
579 					{
580 						check_stmts(cstate, stmt_case->else_stmts, &closing_local, &exceptions_local);
581 						*closing = merge_closing(closing_all_paths,
582 														  closing_local,
583 														  exceptions,
584 														  exceptions_local,
585 														  -1);
586 					}
587 					else
588 						/* is not ensured all path evaluation */
589 						*closing = possibly_closed(closing_all_paths);
590 				}
591 				break;
592 
593 			case PLPGSQL_STMT_LOOP:
594 				check_stmts(cstate, ((PLpgSQL_stmt_loop *) stmt)->body, closing, exceptions);
595 				break;
596 
597 			case PLPGSQL_STMT_WHILE:
598 				{
599 					PLpgSQL_stmt_while *stmt_while = (PLpgSQL_stmt_while *) stmt;
600 					int		closing_local;
601 					List   *exceptions_local;
602 
603 					plpgsql_check_expr_with_scalar_type(cstate,
604 										     stmt_while->cond,
605 										     BOOLOID,
606 										     true);
607 
608 					/*
609 					 * When is not guaranteed execution (possible zero loops),
610 					 * then ignore closing info from body.
611 					 */
612 					check_stmts(cstate, stmt_while->body, &closing_local, &exceptions_local);
613 					*closing = possibly_closed(closing_local);
614 				}
615 				break;
616 
617 			case PLPGSQL_STMT_FORI:
618 				{
619 					PLpgSQL_stmt_fori *stmt_fori = (PLpgSQL_stmt_fori *) stmt;
620 					int			dno = stmt_fori->var->dno;
621 					int		closing_local;
622 					List   *exceptions_local;
623 
624 					/* prepare plan if desn't exist yet */
625 					plpgsql_check_assignment(cstate, stmt_fori->lower, NULL, NULL, dno);
626 					plpgsql_check_assignment(cstate, stmt_fori->upper, NULL, NULL, dno);
627 
628 					if (stmt_fori->step)
629 						plpgsql_check_assignment(cstate, stmt_fori->step, NULL, NULL, dno);
630 
631 					/* this variable should not be updated */
632 					cstate->protected_variables = bms_add_member(cstate->protected_variables, dno);
633 					cstate->auto_variables = bms_add_member(cstate->auto_variables, dno);
634 
635 					check_stmts(cstate, stmt_fori->body, &closing_local, &exceptions_local);
636 					*closing = possibly_closed(closing_local);
637 				}
638 				break;
639 
640 			case PLPGSQL_STMT_FORS:
641 				{
642 					PLpgSQL_stmt_fors *stmt_fors = (PLpgSQL_stmt_fors *) stmt;
643 					int		closing_local;
644 					List   *exceptions_local;
645 
646 #if PG_VERSION_NUM >= 110000
647 
648 					check_variable(cstate, stmt_fors->var);
649 
650 					/* we need to set hidden variable type */
651 					plpgsql_check_assignment_to_variable(cstate, stmt_fors->query,
652 									 stmt_fors->var, -1);
653 
654 #else
655 
656 					plpgsql_check_row_or_rec(cstate, stmt_fors->row, stmt_fors->rec);
657 
658 					/* we need to set hidden variable type */
659 					plpgsql_check_assignment(cstate, stmt_fors->query,
660 									 stmt_fors->rec, stmt_fors->row, -1);
661 
662 #endif
663 
664 					check_stmts(cstate, stmt_fors->body, &closing_local, &exceptions_local);
665 					*closing = possibly_closed(closing_local);
666 				}
667 				break;
668 
669 			case PLPGSQL_STMT_FORC:
670 				{
671 					PLpgSQL_stmt_forc *stmt_forc = (PLpgSQL_stmt_forc *) stmt;
672 					PLpgSQL_var *var = (PLpgSQL_var *) func->datums[stmt_forc->curvar];
673 					int		closing_local;
674 					List   *exceptions_local;
675 
676 #if PG_VERSION_NUM >= 110000
677 
678 					check_variable(cstate, stmt_forc->var);
679 
680 #else
681 
682 					plpgsql_check_row_or_rec(cstate, stmt_forc->row, stmt_forc->rec);
683 
684 #endif
685 
686 					plpgsql_check_expr_as_sqlstmt_data(cstate, stmt_forc->argquery);
687 
688 #if PG_VERSION_NUM >= 110000
689 
690 					if (var->cursor_explicit_expr != NULL)
691 						plpgsql_check_assignment_to_variable(cstate, var->cursor_explicit_expr,
692 										 stmt_forc->var, -1);
693 
694 #else
695 
696 					if (var->cursor_explicit_expr != NULL)
697 						plpgsql_check_assignment(cstate, var->cursor_explicit_expr,
698 										 stmt_forc->rec, stmt_forc->row, -1);
699 
700 #endif
701 
702 					check_stmts(cstate, stmt_forc->body, &closing_local, &exceptions_local);
703 					*closing = possibly_closed(closing_local);
704 
705 					cstate->used_variables = bms_add_member(cstate->used_variables,
706 										 stmt_forc->curvar);
707 				}
708 				break;
709 
710 			case PLPGSQL_STMT_DYNFORS:
711 				{
712 					PLpgSQL_stmt_dynfors *stmt_dynfors = (PLpgSQL_stmt_dynfors *) stmt;
713 					int		closing_local;
714 					List   *exceptions_local;
715 
716 					check_dynamic_sql(cstate,
717 									  stmt,
718 									  stmt_dynfors->query,
719 									  true,
720 
721 #if PG_VERSION_NUM >= 110000
722 
723 									  stmt_dynfors->var,
724 
725 #else
726 
727 									  stmt_dynfors->row,
728 									  stmt_dynfors->rec,
729 
730 #endif
731 
732 									  stmt_dynfors->params);
733 
734 					check_stmts(cstate, stmt_dynfors->body, &closing_local, &exceptions_local);
735 					*closing = possibly_closed(closing_local);
736 				}
737 				break;
738 
739 			case PLPGSQL_STMT_FOREACH_A:
740 				{
741 					PLpgSQL_stmt_foreach_a *stmt_foreach_a = (PLpgSQL_stmt_foreach_a *) stmt;
742 					bool use_element_type;
743 					int		closing_local;
744 					List   *exceptions_local;
745 
746 					plpgsql_check_target(cstate, stmt_foreach_a->varno, NULL, NULL);
747 
748 					/*
749 					 * When slice > 0, then result and target are a array.
750 					 * We shoudl to disable a array element refencing.
751 					 */
752 					use_element_type = stmt_foreach_a->slice == 0;
753 
754 					plpgsql_check_assignment_with_possible_slices(cstate,
755 											 stmt_foreach_a->expr,
756 											 NULL, NULL,
757 											 stmt_foreach_a->varno,
758 											 use_element_type);
759 
760 					check_stmts(cstate, stmt_foreach_a->body, &closing_local, &exceptions_local);
761 					*closing = possibly_closed(closing_local);
762 				}
763 				break;
764 
765 			case PLPGSQL_STMT_EXIT:
766 				{
767 					PLpgSQL_stmt_exit *stmt_exit = (PLpgSQL_stmt_exit *) stmt;
768 
769 					plpgsql_check_expr_with_scalar_type(cstate,
770 										     stmt_exit->cond,
771 										     BOOLOID,
772 										     false);
773 
774 					if (stmt_exit->label != NULL)
775 					{
776 						PLpgSQL_stmt *labeled_stmt = find_stmt_with_label(stmt_exit->label,
777 												    outer_stmt);
778 						if (labeled_stmt == NULL)
779 							ereport(ERROR,
780 								(errcode(ERRCODE_SYNTAX_ERROR),
781 								 errmsg("label \"%s\" does not exist", stmt_exit->label)));
782 
783 						/* CONTINUE only allows loop labels */
784 						if (!is_any_loop_stmt(labeled_stmt) && !stmt_exit->is_exit)
785 							ereport(ERROR,
786 									(errcode(ERRCODE_SYNTAX_ERROR),
787 									 errmsg("block label \"%s\" cannot be used in CONTINUE",
788 									 stmt_exit->label)));
789 					}
790 					else
791 					{
792 						if (find_nearest_loop(outer_stmt) == NULL)
793 							ereport(ERROR,
794 								(errcode(ERRCODE_SYNTAX_ERROR),
795 								 errmsg("%s cannot be used outside a loop",
796 								 plpgsql_check__stmt_typename_p((PLpgSQL_stmt *) stmt_exit))));
797 					}
798 				}
799 				break;
800 
801 			case PLPGSQL_STMT_PERFORM:
802 				plpgsql_check_expr_as_sqlstmt(cstate, ((PLpgSQL_stmt_perform *) stmt)->expr);
803 
804 				/*
805 				 * Note: if you want to raise warning when used expressions returns
806 				 * some value (other than VOID type), change previous command plpgsql_check_expr
807 				 * to following check_expr_with_expected_scalar_type. This should be
808 				 * not enabled by default, because PERFORM can be used with reason
809 				 * to ignore result.
810 				 *
811 				 * check_expr_with_expected_scalar_type(cstate,
812 				 * 					     ((PLpgSQL_stmt_perform *) stmt)->expr,
813 				 * 					     VOIDOID,
814 				 * 					     true);
815 				 */
816 
817 				break;
818 
819 			case PLPGSQL_STMT_RETURN:
820 				{
821 					PLpgSQL_stmt_return *stmt_rt = (PLpgSQL_stmt_return *) stmt;
822 
823 					if (stmt_rt->retvarno >= 0)
824 					{
825 						PLpgSQL_datum *retvar = cstate->estate->datums[stmt_rt->retvarno];
826 						PLpgSQL_execstate *estate = cstate->estate;
827 
828 						cstate->used_variables = bms_add_member(cstate->used_variables, stmt_rt->retvarno);
829 
830 						switch (retvar->dtype)
831 						{
832 							case PLPGSQL_DTYPE_VAR:
833 								{
834 									PLpgSQL_var *var = (PLpgSQL_var *) retvar;
835 
836 									plpgsql_check_assign_to_target_type(cstate,
837 										 cstate->estate->func->fn_rettype, -1,
838 										 var->datatype->typoid, false);
839 								}
840 								break;
841 
842 							case PLPGSQL_DTYPE_REC:
843 								{
844 									PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar;
845 
846 									if (recvar_tupdesc(rec) && estate->rsi && IsA(estate->rsi, ReturnSetInfo))
847 									{
848 										TupleDesc	rettupdesc = estate->rsi->expectedDesc;
849 										TupleConversionMap *tupmap ;
850 
851 										tupmap = convert_tuples_by_position(recvar_tupdesc(rec), rettupdesc,
852 											 gettext_noop("returned record type does not match expected record type"));
853 
854 										if (tupmap)
855 											free_conversion_map(tupmap);
856 									}
857 								}
858 								break;
859 
860 							case PLPGSQL_DTYPE_ROW:
861 								{
862 									PLpgSQL_row *row = (PLpgSQL_row *) retvar;
863 
864 									if (row->rowtupdesc && estate->rsi && IsA(estate->rsi, ReturnSetInfo))
865 									{
866 										TupleDesc	rettupdesc = estate->rsi->expectedDesc;
867 										TupleConversionMap *tupmap ;
868 
869 										tupmap = convert_tuples_by_position(row->rowtupdesc, rettupdesc,
870 											 gettext_noop("returned record type does not match expected record type"));
871 
872 										if (tupmap)
873 											free_conversion_map(tupmap);
874 									}
875 								}
876 								break;
877 
878 							default:
879 								;		/* nope */
880 						}
881 					}
882 
883 					*closing = PLPGSQL_CHECK_CLOSED;
884 
885 					if (stmt_rt->expr)
886 						plpgsql_check_returned_expr(cstate, stmt_rt->expr, true);
887 				}
888 				break;
889 
890 			case PLPGSQL_STMT_RETURN_NEXT:
891 				{
892 					PLpgSQL_stmt_return_next *stmt_rn = (PLpgSQL_stmt_return_next *) stmt;
893 
894 					if (stmt_rn->retvarno >= 0)
895 					{
896 						PLpgSQL_datum *retvar = cstate->estate->datums[stmt_rn->retvarno];
897 						PLpgSQL_execstate *estate = cstate->estate;
898 						int		natts;
899 
900 						cstate->used_variables = bms_add_member(cstate->used_variables, stmt_rn->retvarno);
901 
902 						if (!estate->retisset)
903 							ereport(ERROR,
904 									(errcode(ERRCODE_SYNTAX_ERROR),
905 									 errmsg("cannot use RETURN NEXT in a non-SETOF function")));
906 
907 #if PG_VERSION_NUM >= 110000
908 
909 						tupdesc = estate->tuple_store_desc;
910 
911 #else
912 
913 						tupdesc = estate->rettupdesc;
914 
915 #endif
916 
917 						natts = tupdesc ? tupdesc->natts : 0;
918 
919 						switch (retvar->dtype)
920 						{
921 							case PLPGSQL_DTYPE_VAR:
922 								{
923 									PLpgSQL_var *var = (PLpgSQL_var *) retvar;
924 
925 									if (natts > 1)
926 										ereport(ERROR,
927 												(errcode(ERRCODE_DATATYPE_MISMATCH),
928 												 errmsg("wrong result type supplied in RETURN NEXT")));
929 
930 									plpgsql_check_assign_to_target_type(cstate,
931 										 cstate->estate->func->fn_rettype, -1,
932 										 var->datatype->typoid, false);
933 								}
934 								break;
935 
936 							case PLPGSQL_DTYPE_REC:
937 								{
938 									PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar;
939 									TupleConversionMap *tupmap;
940 
941 									if (!HeapTupleIsValid(recvar_tuple(rec)))
942 										ereport(ERROR,
943 												  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
944 												   errmsg("record \"%s\" is not assigned yet",
945 												   rec->refname),
946 										errdetail("The tuple structure of a not-yet-assigned"
947 															  " record is indeterminate.")));
948 
949 									if (tupdesc)
950 									{
951 										tupmap = convert_tuples_by_position(recvar_tupdesc(rec),
952 																tupdesc,
953 											gettext_noop("wrong record type supplied in RETURN NEXT"));
954 										if (tupmap)
955 											free_conversion_map(tupmap);
956 									}
957 								}
958 								break;
959 
960 							case PLPGSQL_DTYPE_ROW:
961 								{
962 									PLpgSQL_row *row = (PLpgSQL_row *) retvar;
963 									bool	row_is_valid_result;
964 
965 									row_is_valid_result = true;
966 
967 									if (tupdesc)
968 									{
969 										if (row->nfields == natts)
970 										{
971 											int		i;
972 
973 											for (i = 0; i < natts; i++)
974 											{
975 												PLpgSQL_var *var;
976 
977 												if (TupleDescAttr(tupdesc, i)->attisdropped)
978 													continue;
979 												if (row->varnos[i] < 0)
980 													elog(ERROR, "dropped rowtype entry for non-dropped column");
981 
982 												var = (PLpgSQL_var *) (cstate->estate->datums[row->varnos[i]]);
983 												if (var->datatype->typoid != TupleDescAttr(tupdesc, i)->atttypid)
984 												{
985 													row_is_valid_result = false;
986 													break;
987 												}
988 											}
989 										}
990 										else
991 											row_is_valid_result = false;
992 
993 										if (!row_is_valid_result)
994 											ereport(ERROR,
995 													(errcode(ERRCODE_DATATYPE_MISMATCH),
996 											errmsg("wrong record type supplied in RETURN NEXT")));
997 									}
998 								}
999 								break;
1000 
1001 							default:
1002 								;		/* nope */
1003 						}
1004 					}
1005 
1006 					if (stmt_rn->expr)
1007 						plpgsql_check_returned_expr(cstate, stmt_rn->expr, true);
1008 				}
1009 				break;
1010 
1011 			case PLPGSQL_STMT_RETURN_QUERY:
1012 				{
1013 					PLpgSQL_stmt_return_query *stmt_rq = (PLpgSQL_stmt_return_query *) stmt;
1014 
1015 					if (stmt_rq->query)
1016 					{
1017 						plpgsql_check_returned_expr(cstate, stmt_rq->query, false);
1018 						cstate->found_return_query = true;
1019 					}
1020 
1021 					if (stmt_rq->dynquery)
1022 					{
1023 						check_dynamic_sql(cstate,
1024 										  stmt,
1025 										  stmt_rq->dynquery,
1026 										  false,
1027 
1028 #if PG_VERSION_NUM >= 110000
1029 
1030 										  NULL,
1031 
1032 #else
1033 
1034 										  NULL, NULL,
1035 
1036 #endif
1037 
1038 										  stmt_rq->params);
1039 					}
1040 				}
1041 				break;
1042 
1043 			case PLPGSQL_STMT_RAISE:
1044 				{
1045 					PLpgSQL_stmt_raise *stmt_raise = (PLpgSQL_stmt_raise *) stmt;
1046 					ListCell   *current_param;
1047 					ListCell   *l;
1048 					char	   *cp;
1049 					int			err_code = 0;
1050 
1051 					if (stmt_raise->condname != NULL)
1052 						err_code = plpgsql_check__recognize_err_condition_p(stmt_raise->condname, true);
1053 
1054 					foreach(l, stmt_raise->params)
1055 					{
1056 						plpgsql_check_expr(cstate, (PLpgSQL_expr *) lfirst(l));
1057 					}
1058 
1059 					foreach(l, stmt_raise->options)
1060 					{
1061 						PLpgSQL_raise_option *opt = (PLpgSQL_raise_option *) lfirst(l);
1062 
1063 						plpgsql_check_expr(cstate, opt->expr);
1064 
1065 						if (opt->opt_type == PLPGSQL_RAISEOPTION_ERRCODE)
1066 						{
1067 							bool		isnull;
1068 							char	   *value;
1069 
1070 							value = plpgsql_check_expr_get_string(cstate, opt->expr, &isnull);
1071 
1072 							if (value != NULL)
1073 								err_code = plpgsql_check__recognize_err_condition_p(value, true);
1074 							else
1075 								err_code = -1;		/* cannot be calculated now */
1076 						}
1077 					}
1078 
1079 					current_param = list_head(stmt_raise->params);
1080 
1081 					/* ensure any single % has a own parameter */
1082 					if (stmt_raise->message != NULL)
1083 					{
1084 						for (cp = stmt_raise->message; *cp; cp++)
1085 						{
1086 							if (cp[0] == '%')
1087 							{
1088 								if (cp[1] == '%')
1089 								{
1090 									cp++;
1091 									continue;
1092 								}
1093 								if (current_param == NULL)
1094 									ereport(ERROR,
1095 											(errcode(ERRCODE_SYNTAX_ERROR),
1096 											 errmsg("too few parameters specified for RAISE")));
1097 
1098 #if PG_VERSION_NUM >= 130000
1099 
1100 								current_param = lnext(stmt_raise->params, current_param);
1101 
1102 #else
1103 
1104 								current_param = lnext(current_param);
1105 
1106 #endif
1107 
1108 							}
1109 						}
1110 					}
1111 					if (current_param != NULL)
1112 						ereport(ERROR,
1113 								(errcode(ERRCODE_SYNTAX_ERROR),
1114 						 errmsg("too many parameters specified for RAISE")));
1115 
1116 					if (stmt_raise->elog_level >= ERROR)
1117 					{
1118 						*closing = PLPGSQL_CHECK_CLOSED_BY_EXCEPTIONS;
1119 						if (err_code == 0)
1120 							err_code = ERRCODE_RAISE_EXCEPTION;
1121 						else if (err_code == -1)
1122 							err_code = 0; /* cannot be calculated */
1123 						*exceptions = list_make1_int(err_code);
1124 					}
1125 					/* without any parameters it is reRAISE */
1126 					if (stmt_raise->condname == NULL && stmt_raise->message == NULL &&
1127 						stmt_raise->options == NIL)
1128 					{
1129 						*closing = PLPGSQL_CHECK_CLOSED_BY_EXCEPTIONS;
1130 						/* should be enhanced in future */
1131 						*exceptions = list_make1_int(-2); /* reRAISE */
1132 					}
1133 				}
1134 				break;
1135 
1136 			case PLPGSQL_STMT_EXECSQL:
1137 				{
1138 					PLpgSQL_stmt_execsql *stmt_execsql = (PLpgSQL_stmt_execsql *) stmt;
1139 
1140 					if (stmt_execsql->into)
1141 					{
1142 
1143 #if PG_VERSION_NUM >= 110000
1144 
1145 						check_variable(cstate, stmt_execsql->target);
1146 						plpgsql_check_assignment_to_variable(cstate, stmt_execsql->sqlstmt,
1147 													  stmt_execsql->target, -1);
1148 
1149 #else
1150 
1151 						plpgsql_check_row_or_rec(cstate, stmt_execsql->row, stmt_execsql->rec);
1152 						plpgsql_check_assignment(cstate, stmt_execsql->sqlstmt,
1153 								   stmt_execsql->rec, stmt_execsql->row, -1);
1154 
1155 #endif
1156 
1157 					}
1158 					else
1159 						/* only statement */
1160 						plpgsql_check_expr_as_sqlstmt_nodata(cstate, stmt_execsql->sqlstmt);
1161 				}
1162 				break;
1163 
1164 			case PLPGSQL_STMT_DYNEXECUTE:
1165 				{
1166 					PLpgSQL_stmt_dynexecute *stmt_dynexecute = (PLpgSQL_stmt_dynexecute *) stmt;
1167 
1168 					check_dynamic_sql(cstate,
1169 									  stmt,
1170 									  stmt_dynexecute->query,
1171 									  stmt_dynexecute->into,
1172 
1173 #if PG_VERSION_NUM >= 110000
1174 
1175 									  stmt_dynexecute->target,
1176 
1177 #else
1178 
1179 									  stmt_dynexecute->row,
1180 									  stmt_dynexecute->rec,
1181 
1182 #endif
1183 
1184 									  stmt_dynexecute->params);
1185 				}
1186 				break;
1187 
1188 			case PLPGSQL_STMT_OPEN:
1189 				{
1190 					PLpgSQL_stmt_open *stmt_open = (PLpgSQL_stmt_open *) stmt;
1191 					PLpgSQL_var *var = (PLpgSQL_var *) (cstate->estate->datums[stmt_open->curvar]);
1192 					ListCell	*l;
1193 
1194 					plpgsql_check_expr_as_sqlstmt_data(cstate, var->cursor_explicit_expr);
1195 					plpgsql_check_expr_as_sqlstmt_data(cstate, stmt_open->query);
1196 
1197 					if (stmt_open->query != NULL)
1198 						var->cursor_explicit_expr = stmt_open->query;
1199 
1200 					plpgsql_check_expr_as_sqlstmt_data(cstate, stmt_open->argquery);
1201 
1202 					plpgsql_check_expr(cstate, stmt_open->dynquery);
1203 
1204 					foreach(l, stmt_open->params)
1205 					{
1206 						plpgsql_check_expr(cstate, (PLpgSQL_expr *) lfirst(l));
1207 					}
1208 
1209 					cstate->modif_variables = bms_add_member(cstate->modif_variables,
1210 									 stmt_open->curvar);
1211 				}
1212 				break;
1213 
1214 			case PLPGSQL_STMT_GETDIAG:
1215 				{
1216 					PLpgSQL_stmt_getdiag *stmt_getdiag = (PLpgSQL_stmt_getdiag *) stmt;
1217 					ListCell   *lc;
1218 
1219 					foreach(lc, stmt_getdiag->diag_items)
1220 					{
1221 						PLpgSQL_diag_item *diag_item = (PLpgSQL_diag_item *) lfirst(lc);
1222 
1223 						plpgsql_check_target(cstate, diag_item->target, NULL, NULL);
1224 					}
1225 				}
1226 				break;
1227 
1228 			case PLPGSQL_STMT_FETCH:
1229 				{
1230 					PLpgSQL_stmt_fetch *stmt_fetch = (PLpgSQL_stmt_fetch *) stmt;
1231 					PLpgSQL_var *var = (PLpgSQL_var *) (cstate->estate->datums[stmt_fetch->curvar]);
1232 
1233 #if PG_VERSION_NUM >= 110000
1234 
1235 					check_variable(cstate, stmt_fetch->target);
1236 
1237 					if (var != NULL && var->cursor_explicit_expr != NULL)
1238 						plpgsql_check_assignment_to_variable(cstate, var->cursor_explicit_expr,
1239 									   stmt_fetch->target, -1);
1240 
1241 #else
1242 
1243 					plpgsql_check_row_or_rec(cstate, stmt_fetch->row, stmt_fetch->rec);
1244 
1245 					if (var != NULL && var->cursor_explicit_expr != NULL)
1246 						plpgsql_check_assignment(cstate, var->cursor_explicit_expr,
1247 									   stmt_fetch->rec, stmt_fetch->row, -1);
1248 
1249 #endif
1250 
1251 					plpgsql_check_expr(cstate, stmt_fetch->expr);
1252 
1253 					cstate->used_variables = bms_add_member(cstate->used_variables, stmt_fetch->curvar);
1254 				}
1255 				break;
1256 
1257 			case PLPGSQL_STMT_CLOSE:
1258 				cstate->used_variables = bms_add_member(cstate->used_variables,
1259 								 ((PLpgSQL_stmt_close *) stmt)->curvar);
1260 
1261 				break;
1262 
1263 #if PG_VERSION_NUM >= 110000
1264 
1265 #if PG_VERSION_NUM < 140000
1266 			case PLPGSQL_STMT_SET:
1267 				/*
1268 				 * We can not check this now, syntax should be ok.
1269 				 * The expression there has not plan.
1270 				 */
1271 				break;
1272 #endif			/* PG_VERSION_NUM < 140000 */
1273 
1274 			case PLPGSQL_STMT_COMMIT:
1275 			case PLPGSQL_STMT_ROLLBACK:
1276 				/* These commands are allowed only in procedures */
1277 				if (!cstate->cinfo->is_procedure)
1278 					ereport(ERROR,
1279 							(errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
1280 							 errmsg("invalid transaction termination")));
1281 				break;
1282 
1283 			case PLPGSQL_STMT_CALL:
1284 				{
1285 					PLpgSQL_stmt_call *stmt_call = (PLpgSQL_stmt_call *) stmt;
1286 					PLpgSQL_row *target;
1287 					bool		has_data;
1288 
1289 					has_data = plpgsql_check_expr_as_sqlstmt(cstate, stmt_call->expr);
1290 
1291 					/* any check_expr_xxx should be called before CallExprGetRowTarget */
1292 					target = plpgsql_check_CallExprGetRowTarget(cstate, stmt_call->expr);
1293 
1294 					if (has_data != (target != NULL))
1295 						elog(ERROR, "plpgsql internal error, broken CALL statement");
1296 
1297 					if (target != NULL)
1298 					{
1299 						check_variable(cstate, (PLpgSQL_variable *) target);
1300 						plpgsql_check_assignment_to_variable(cstate, stmt_call->expr,
1301 																(PLpgSQL_variable *) target, -1);
1302 
1303 						pfree(target->varnos);
1304 						pfree(target);
1305 					}
1306 				}
1307 				break;
1308 
1309 #endif			/* PG_VERSION_NUM >= 110000 */
1310 
1311 			default:
1312 				elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
1313 		}
1314 
1315 		pop_stmt_from_stmt_stack(cstate);
1316 
1317 		ReleaseCurrentSubTransaction();
1318 		MemoryContextSwitchTo(oldCxt);
1319 		CurrentResourceOwner = oldowner;
1320 
1321 		SPI_restore_connection();
1322 	}
1323 	PG_CATCH();
1324 	{
1325 		ErrorData  *edata;
1326 
1327 		MemoryContextSwitchTo(oldCxt);
1328 		edata = CopyErrorData();
1329 		FlushErrorState();
1330 
1331 		RollbackAndReleaseCurrentSubTransaction();
1332 		MemoryContextSwitchTo(oldCxt);
1333 		CurrentResourceOwner = oldowner;
1334 
1335 		pop_stmt_from_stmt_stack(cstate);
1336 
1337 		if (!cstate->pragma_vector.disable_check)
1338 		{
1339 			/*
1340 			 * If fatal_errors is true, we just propagate the error up to the
1341 			 * highest level. Otherwise the error is appended to our current list
1342 			 * of errors, and we continue checking.
1343 			 */
1344 			if (cstate->cinfo->fatal_errors)
1345 				ReThrowError(edata);
1346 			else
1347 				plpgsql_check_put_error_edata(cstate, edata);
1348 		}
1349 
1350 		MemoryContextSwitchTo(oldCxt);
1351 
1352 		/* reconnect spi */
1353 		SPI_restore_connection();
1354 	}
1355 	PG_END_TRY();
1356 
1357 	if (!cstate->was_pragma)
1358 		cstate->pragma_vector = pragma_vector;
1359 	else
1360 		cstate->was_pragma = false;
1361 }
1362 
1363 /*
1364  * Ensure check for all statements in list
1365  *
1366  */
1367 static void
check_stmts(PLpgSQL_checkstate * cstate,List * stmts,int * closing,List ** exceptions)1368 check_stmts(PLpgSQL_checkstate *cstate, List *stmts, int *closing, List **exceptions)
1369 {
1370 	ListCell   *lc;
1371 	int			closing_local;
1372 	List	   *exceptions_local;
1373 	volatile bool		dead_code_alert = false;
1374 	plpgsql_check_pragma_vector		prev_pragma_vector = cstate->pragma_vector;
1375 
1376 	*closing = PLPGSQL_CHECK_UNCLOSED;
1377 	*exceptions = NIL;
1378 
1379 	PG_TRY();
1380 	{
1381 		foreach(lc, stmts)
1382 		{
1383 			PLpgSQL_stmt	   *stmt = (PLpgSQL_stmt *) lfirst(lc);
1384 
1385 			closing_local = PLPGSQL_CHECK_UNCLOSED;
1386 			exceptions_local = NIL;
1387 
1388 			plpgsql_check_stmt(cstate, stmt, &closing_local, &exceptions_local);
1389 
1390 			/* raise dead_code_alert only for visible statements */
1391 			if (dead_code_alert && stmt->lineno > 0)
1392 			{
1393 				plpgsql_check_put_error(cstate,
1394 							  0, stmt->lineno,
1395 							  "unreachable code",
1396 							  NULL,
1397 							  NULL,
1398 							  PLPGSQL_CHECK_WARNING_EXTRA,
1399 							  0, NULL, NULL);
1400 				/* don't raise this warning every line */
1401 				dead_code_alert = false;
1402 			}
1403 
1404 			if (closing_local == PLPGSQL_CHECK_CLOSED)
1405 			{
1406 				dead_code_alert = true;
1407 				*closing = PLPGSQL_CHECK_CLOSED;
1408 				*exceptions = NIL;
1409 			}
1410 			else if (closing_local == PLPGSQL_CHECK_CLOSED_BY_EXCEPTIONS)
1411 			{
1412 				dead_code_alert = true;
1413 				if (*closing == PLPGSQL_CHECK_UNCLOSED ||
1414 					*closing == PLPGSQL_CHECK_POSSIBLY_CLOSED ||
1415 					*closing == PLPGSQL_CHECK_CLOSED_BY_EXCEPTIONS)
1416 				{
1417 					*closing = PLPGSQL_CHECK_CLOSED_BY_EXCEPTIONS;
1418 					*exceptions = exceptions_local;
1419 				}
1420 			}
1421 			else if (closing_local == PLPGSQL_CHECK_POSSIBLY_CLOSED)
1422 			{
1423 				if (*closing == PLPGSQL_CHECK_UNCLOSED)
1424 				{
1425 					*closing = PLPGSQL_CHECK_POSSIBLY_CLOSED;
1426 					*exceptions = NIL;
1427 				}
1428 			}
1429 		}
1430 	}
1431 	PG_CATCH();
1432 	{
1433 		cstate->pragma_vector = prev_pragma_vector;
1434 		cstate->was_pragma = false;
1435 
1436 		PG_RE_THROW();
1437 	}
1438 	PG_END_TRY();
1439 }
1440 
1441 /*
1442  * Add label to stack of labels
1443  */
1444 static PLpgSQL_stmt_stack_item *
push_stmt_to_stmt_stack(PLpgSQL_checkstate * cstate)1445 push_stmt_to_stmt_stack(PLpgSQL_checkstate *cstate)
1446 {
1447 	PLpgSQL_stmt *stmt = cstate->estate->err_stmt;
1448 	PLpgSQL_stmt_stack_item *stmt_stack_item;
1449 	PLpgSQL_stmt_stack_item *current = cstate->top_stmt_stack;
1450 
1451 	stmt_stack_item = (PLpgSQL_stmt_stack_item *) palloc(sizeof(PLpgSQL_stmt_stack_item));
1452 	stmt_stack_item->stmt = stmt;
1453 
1454 	switch (PLPGSQL_STMT_TYPES stmt->cmd_type)
1455 	{
1456 		case PLPGSQL_STMT_BLOCK:
1457 			stmt_stack_item->label = ((PLpgSQL_stmt_block *) stmt)->label;
1458 			break;
1459 
1460 		case PLPGSQL_STMT_EXIT:
1461 			stmt_stack_item->label = ((PLpgSQL_stmt_exit *) stmt)->label;
1462 			break;
1463 
1464 		case PLPGSQL_STMT_LOOP:
1465 			stmt_stack_item->label = ((PLpgSQL_stmt_loop *) stmt)->label;
1466 			break;
1467 
1468 		case PLPGSQL_STMT_WHILE:
1469 			stmt_stack_item->label = ((PLpgSQL_stmt_while *) stmt)->label;
1470 			break;
1471 
1472 		case PLPGSQL_STMT_FORI:
1473 			stmt_stack_item->label = ((PLpgSQL_stmt_fori *) stmt)->label;
1474 			break;
1475 
1476 		case PLPGSQL_STMT_FORS:
1477 			stmt_stack_item->label = ((PLpgSQL_stmt_fors *) stmt)->label;
1478 			break;
1479 
1480 		case PLPGSQL_STMT_FORC:
1481 			stmt_stack_item->label = ((PLpgSQL_stmt_forc *) stmt)->label;
1482 			break;
1483 
1484 		case PLPGSQL_STMT_DYNFORS:
1485 			stmt_stack_item->label = ((PLpgSQL_stmt_dynfors *) stmt)->label;
1486 			break;
1487 
1488 		case PLPGSQL_STMT_FOREACH_A:
1489 			stmt_stack_item->label = ((PLpgSQL_stmt_foreach_a *) stmt)->label;
1490 			break;
1491 
1492 		default:
1493 			stmt_stack_item->label = NULL;
1494 	}
1495 
1496 	stmt_stack_item->outer = current;
1497 	cstate->top_stmt_stack = stmt_stack_item;
1498 
1499 	return current;
1500 }
1501 
1502 static void
pop_stmt_from_stmt_stack(PLpgSQL_checkstate * cstate)1503 pop_stmt_from_stmt_stack(PLpgSQL_checkstate *cstate)
1504 {
1505 	PLpgSQL_stmt_stack_item *current = cstate->top_stmt_stack;
1506 
1507 	Assert(cstate->top_stmt_stack != NULL);
1508 
1509 	cstate->top_stmt_stack = current->outer;
1510 	pfree(current);
1511 }
1512 
1513 /*
1514  * Returns true, when stmt is any loop statement
1515  */
1516 static bool
is_any_loop_stmt(PLpgSQL_stmt * stmt)1517 is_any_loop_stmt(PLpgSQL_stmt *stmt)
1518 {
1519 	switch (PLPGSQL_STMT_TYPES stmt->cmd_type)
1520 	{
1521 		case PLPGSQL_STMT_LOOP:
1522 		case PLPGSQL_STMT_WHILE:
1523 		case PLPGSQL_STMT_FORI:
1524 		case PLPGSQL_STMT_FORS:
1525 		case PLPGSQL_STMT_FORC:
1526 		case PLPGSQL_STMT_DYNFORS:
1527 		case PLPGSQL_STMT_FOREACH_A:
1528 			return true;
1529 		default:
1530 			return false;
1531 	}
1532 }
1533 
1534 /*
1535  * Searching a any statement related to CONTINUE/EXIT statement.
1536  * label cannot be NULL.
1537  */
1538 static PLpgSQL_stmt *
find_stmt_with_label(char * label,PLpgSQL_stmt_stack_item * current)1539 find_stmt_with_label(char *label, PLpgSQL_stmt_stack_item *current)
1540 {
1541 	while (current != NULL)
1542 	{
1543 		if (current->label != NULL
1544 				&& strcmp(current->label, label) == 0)
1545 			return current->stmt;
1546 
1547 		current = current->outer;
1548 	}
1549 
1550 	return NULL;
1551 }
1552 
1553 static PLpgSQL_stmt *
find_nearest_loop(PLpgSQL_stmt_stack_item * current)1554 find_nearest_loop(PLpgSQL_stmt_stack_item *current)
1555 {
1556 	while (current != NULL)
1557 	{
1558 		if (is_any_loop_stmt(current->stmt))
1559 			return current->stmt;
1560 
1561 		current = current->outer;
1562 	}
1563 
1564 	return NULL;
1565 }
1566 
1567 /*
1568  * returns false, when a variable doesn't shadows any other variable
1569  */
1570 static bool
found_shadowed_variable(char * varname,PLpgSQL_stmt_stack_item * current,PLpgSQL_checkstate * cstate)1571 found_shadowed_variable(char *varname, PLpgSQL_stmt_stack_item *current, PLpgSQL_checkstate *cstate)
1572 {
1573 	while (current != NULL)
1574 	{
1575 		if (current->stmt->cmd_type == PLPGSQL_STMT_BLOCK)
1576 		{
1577 			PLpgSQL_stmt_block *stmt_block = (PLpgSQL_stmt_block *) current->stmt;
1578 			int			i;
1579 			PLpgSQL_datum *d;
1580 
1581 			for (i = 0; i < stmt_block->n_initvars; i++)
1582 			{
1583 				char	   *refname;
1584 
1585 				d = cstate->estate->func->datums[stmt_block->initvarnos[i]];
1586 				refname = plpgsql_check_datum_get_refname(d);
1587 
1588 				if (refname != NULL && strcmp(refname, varname) == 0)
1589 					return true;
1590 			}
1591 		}
1592 
1593 		current = current->outer;
1594 	}
1595 
1596 	return false;
1597 }
1598 
1599 /*
1600  * Reduce ending states of execution paths.
1601  *
1602  */
1603 static int
possibly_closed(int c)1604 possibly_closed(int c)
1605 {
1606 	switch (c)
1607 	{
1608 		case PLPGSQL_CHECK_CLOSED:
1609 		case PLPGSQL_CHECK_CLOSED_BY_EXCEPTIONS:
1610 		case PLPGSQL_CHECK_POSSIBLY_CLOSED:
1611 			return PLPGSQL_CHECK_POSSIBLY_CLOSED;
1612 		default:
1613 			return PLPGSQL_CHECK_UNCLOSED;
1614 	}
1615 }
1616 
1617 /*
1618  * Deduce ending state of execution paths.
1619  *
1620  */
1621 static int
merge_closing(int c,int c_local,List ** exceptions,List * exceptions_local,int err_code)1622 merge_closing(int c, int c_local, List **exceptions, List *exceptions_local, int err_code)
1623 {
1624 	*exceptions = NIL;
1625 
1626 	if (c == PLPGSQL_CHECK_UNKNOWN)
1627 	{
1628 		if (c_local == PLPGSQL_CHECK_CLOSED_BY_EXCEPTIONS)
1629 			*exceptions = exceptions_local;
1630 
1631 		return c_local;
1632 	}
1633 
1634 	if (c_local == PLPGSQL_CHECK_UNKNOWN)
1635 		return c;
1636 
1637 	if (c == c_local)
1638 	{
1639 		if (c == PLPGSQL_CHECK_CLOSED_BY_EXCEPTIONS)
1640 		{
1641 
1642 			if (err_code != -1)
1643 			{
1644 				ListCell *lc;
1645 
1646 				/* replace reRAISE symbol (-2) by real err_code */
1647 				foreach(lc, exceptions_local)
1648 				{
1649 					int		t_err_code = lfirst_int(lc);
1650 
1651 					*exceptions = list_append_unique_int(*exceptions,
1652 														t_err_code != -2 ? t_err_code : err_code);
1653 				}
1654 			}
1655 			else
1656 				*exceptions = list_concat_unique_int(*exceptions, exceptions_local);
1657 		}
1658 
1659 		return c_local;
1660 	}
1661 
1662 	if (c == PLPGSQL_CHECK_CLOSED || c_local == PLPGSQL_CHECK_CLOSED)
1663 	{
1664 		if (c == PLPGSQL_CHECK_CLOSED_BY_EXCEPTIONS ||
1665 			c_local == PLPGSQL_CHECK_CLOSED_BY_EXCEPTIONS)
1666 		return PLPGSQL_CHECK_CLOSED;
1667 	}
1668 
1669 	return PLPGSQL_CHECK_POSSIBLY_CLOSED;
1670 }
1671 
1672 /*
1673  * Returns true, if exception with sqlerrstate is handled.
1674  *
1675  */
1676 static bool
exception_matches_conditions(int sqlerrstate,PLpgSQL_condition * cond)1677 exception_matches_conditions(int sqlerrstate, PLpgSQL_condition *cond)
1678 {
1679 	for (; cond != NULL; cond = cond->next)
1680 	{
1681 		int			_sqlerrstate = cond->sqlerrstate;
1682 
1683 		/*
1684 		 * OTHERS matches everything *except* query-canceled and
1685 		 * assert-failure.  If you're foolish enough, you can match those
1686 		 * explicitly.
1687 		 */
1688 		if (_sqlerrstate == 0)
1689 		{
1690 			if (sqlerrstate != ERRCODE_QUERY_CANCELED &&
1691 				 sqlerrstate != ERRCODE_ASSERT_FAILURE)
1692 				return true;
1693 		}
1694 		/* Exact match? */
1695 		else if (sqlerrstate == _sqlerrstate)
1696 			return true;
1697 		/* Category match? */
1698 		else if (ERRCODE_IS_CATEGORY(_sqlerrstate) &&
1699 				 ERRCODE_TO_CATEGORY(sqlerrstate) == _sqlerrstate)
1700 			return true;
1701 	}
1702 	return false;
1703 }
1704 
1705 /*
1706  * Dynamic SQL processing.
1707  *
1708  * When dynamic query is constant, we can do same work like with
1709  * static SQL.
1710  */
1711 
1712 typedef struct
1713 {
1714 	List			   *args;
1715 	PLpgSQL_checkstate *cstate;
1716 	bool	use_params;
1717 } DynSQLParams;
1718 
1719 static Node *
dynsql_param_ref(ParseState * pstate,ParamRef * pref)1720 dynsql_param_ref(ParseState *pstate, ParamRef *pref)
1721 {
1722 	DynSQLParams *params = (DynSQLParams *) pstate->p_ref_hook_state;
1723 	List	   *args = params->args;
1724 	int			nargs = list_length(args);
1725 	Param	   *param = NULL;
1726 	PLpgSQL_expr *expr;
1727 	TupleDesc	tupdesc;
1728 
1729 	if (pref->number < 1 || pref->number > nargs)
1730 		ereport(ERROR,
1731 				(errcode(ERRCODE_UNDEFINED_PARAMETER),
1732 				 errmsg("there is no parameter $%d", pref->number),
1733 				 parser_errposition(pstate, pref->location)));
1734 
1735 	expr = (PLpgSQL_expr *) list_nth(args, pref->number - 1);
1736 
1737 	tupdesc = plpgsql_check_expr_get_desc(params->cstate,
1738 										  expr,
1739 										  false,
1740 										  false,
1741 										  true,
1742 										  NULL);
1743 
1744 	if (tupdesc)
1745 	{
1746 		param = makeNode(Param);
1747 		param->paramkind = PARAM_EXTERN;
1748 		param->paramid = pref->number;
1749 		param->paramtype = TupleDescAttr(tupdesc, 0)->atttypid;
1750 		param->location = pref->location;
1751 
1752 		/*
1753 		 * SPI_execute_with_args doesn't allow pass typmod.
1754 		 */
1755 		param->paramtypmod = -1;
1756 		param->paramcollid = InvalidOid;
1757 
1758 		ReleaseTupleDesc(tupdesc);
1759 	}
1760 	else
1761 		elog(ERROR, "cannot to detect type of $%d parameter", pref->number);
1762 
1763 	params->use_params = true;
1764 
1765 	return (Node *) param;
1766 }
1767 
1768 /*
1769  * Dynamic query requires own setup. In reality it is executed by
1770  * different SPI, here we need to emulate different environment.
1771  * Parameters are not mapped to function parameters, but to USING
1772  * clause expressions.
1773  */
1774 static void
dynsql_parser_setup(struct ParseState * pstate,DynSQLParams * params)1775 dynsql_parser_setup(struct ParseState *pstate, DynSQLParams *params)
1776 {
1777 	pstate->p_pre_columnref_hook = NULL;
1778 	pstate->p_post_columnref_hook = NULL;
1779 	pstate->p_paramref_hook = dynsql_param_ref;
1780 	pstate->p_ref_hook_state = (void *) params;
1781 }
1782 
1783 /*
1784  * Returns true if record variable has assigned some type
1785  */
1786 static bool
has_assigned_tupdesc(PLpgSQL_checkstate * cstate,PLpgSQL_rec * rec)1787 has_assigned_tupdesc(PLpgSQL_checkstate *cstate, PLpgSQL_rec *rec)
1788 {
1789 	PLpgSQL_rec *target = (PLpgSQL_rec *) (cstate->estate->datums[rec->dno]);
1790 
1791 	Assert(rec->dtype == PLPGSQL_DTYPE_REC);
1792 
1793 	if (recvar_tupdesc(target))
1794 		return true;
1795 
1796 	return false;
1797 }
1798 
1799 static void
check_dynamic_sql(PLpgSQL_checkstate * cstate,PLpgSQL_stmt * stmt,PLpgSQL_expr * query,bool into,PLpgSQL_variable * target,List * params)1800 check_dynamic_sql(PLpgSQL_checkstate *cstate,
1801 				  PLpgSQL_stmt *stmt,
1802 				  PLpgSQL_expr *query,
1803 				  bool into,
1804 
1805 #if PG_VERSION_NUM >= 110000
1806 
1807 				  PLpgSQL_variable *target,
1808 
1809 #else
1810 
1811 				  PLpgSQL_row *row,
1812 				  PLpgSQL_rec *rec,
1813 
1814 #endif
1815 
1816 				  List *params)
1817 {
1818 	Node	   *expr_node;
1819 	ListCell   *l;
1820 	int			loc = -1;
1821 	char	   *dynquery = NULL;
1822 	bool		prev_has_execute_stmt = cstate->has_execute_stmt;
1823 	volatile bool expr_is_const = false;
1824 
1825 	volatile bool raise_unknown_rec_warning = false;
1826 	volatile bool known_type_of_dynexpr = false;
1827 
1828 	/*
1829 	 * possible checks:
1830 	 *
1831 	 * 1. When expression is string literal, then we can check this query similary
1832 	 *    like cursor query with parameters. When this query has not a parameters,
1833 	 *    and it is not DDL, DML, then we can raise a performance warning'.
1834 	 *
1835 	 * 2. When expression is real expression, then we should to check any string
1836 	 *    kind parameters if are sanitized by functions quote_ident, qoute_literal,
1837 	 *    or format.
1838 	 *
1839 	 * 3. When expression is based on calling format function, and there are used
1840 	 *    only placeholders %I and %L, then we can try to check syntax of embeded
1841 	 *    query.
1842 	 */
1843 
1844 	cstate->has_execute_stmt = true;
1845 
1846 	foreach(l, params)
1847 	{
1848 		plpgsql_check_expr(cstate, (PLpgSQL_expr *) lfirst(l));
1849 	}
1850 
1851 	plpgsql_check_expr(cstate, query);
1852 	expr_node = plpgsql_check_expr_get_node(cstate, query, false);
1853 
1854 	if (IsA(expr_node, FuncExpr))
1855 	{
1856 		FuncExpr *fexpr = (FuncExpr *) expr_node;
1857 
1858 		if (fexpr->funcid == FORMAT_0PARAM_OID ||
1859 			fexpr->funcid == FORMAT_NPARAM_OID)
1860 		{
1861 			if (fexpr->args && IsA(linitial(fexpr->args), Const))
1862 			{
1863 				StringInfoData	sinfo;
1864 				char		c, *fmt;
1865 				bool		subst_is_ok = true;
1866 				bool		found_ident_placeholder = false;
1867 				bool		found_literal_placeholder = false;
1868 
1869 				expr_is_const = fexpr->funcid == FORMAT_0PARAM_OID;
1870 				fmt = plpgsql_check_const_to_string((Const *) linitial(fexpr->args));
1871 
1872 				/*
1873 				 * The placeholders can be used only in FORMAT_NPARAM function,
1874 				 * but for simplicity and consistency we check FORMAT_0PARAM and
1875 				 * FORMAT_NPARAM together
1876 				 */
1877 				initStringInfo(&sinfo);
1878 
1879 				while ((c = *fmt++))
1880 				{
1881 					if (c == '%')
1882 					{
1883 						c = *fmt++;
1884 
1885 						if (c == '%')
1886 						{
1887 							appendStringInfoChar(&sinfo, c);
1888 						}
1889 						else if (c == 'I')
1890 						{
1891 							appendStringInfoString(&sinfo, "\"%I\"");
1892 							expr_is_const = false;
1893 							found_ident_placeholder = true;
1894 						}
1895 						else if (c == 'L')
1896 						{
1897 							/*
1898 							 * Original idea was used external parameter,
1899 							 * but external parameters requires known type,
1900 							 * so most safe value is NULL instead.
1901 							 */
1902 							appendStringInfo(&sinfo, " null ");
1903 							found_literal_placeholder = false;
1904 							expr_is_const = false;
1905 						}
1906 						else
1907 						{
1908 							/*
1909 							 * Because %s is used, we know nothing about form
1910 							 * of output string, and has not any sense to continue
1911 							 * in check.
1912 							 */
1913 							subst_is_ok = false;
1914 							expr_is_const = false;
1915 							break;
1916 						}
1917 					}
1918 					else
1919 						appendStringInfoChar(&sinfo, c);
1920 				}
1921 
1922 				if (subst_is_ok)
1923 				{
1924 					if (!found_literal_placeholder)
1925 					{
1926 
1927 #if PG_VERSION_NUM >= 140000
1928 
1929 						/* in this case we can do only basic parser check */
1930 						raw_parser(sinfo.data, RAW_PARSE_DEFAULT);
1931 
1932 #else
1933 
1934 						raw_parser(sinfo.data);
1935 
1936 #endif
1937 
1938 					}
1939 
1940 					if (!found_ident_placeholder)
1941 						dynquery = sinfo.data;
1942 				}
1943 			}
1944 		}
1945 	}
1946 	else if (IsA(expr_node, Const))
1947 	{
1948 		expr_is_const = true;
1949 		dynquery = plpgsql_check_const_to_string((Const *) expr_node);
1950 	}
1951 
1952 	if (dynquery)
1953 	{
1954 		PLpgSQL_expr *dynexpr = NULL;
1955 		DynSQLParams dsp;
1956 		volatile bool		is_mp;
1957 		volatile bool is_ok = true;
1958 
1959 		dynexpr = palloc0(sizeof(PLpgSQL_expr));
1960 
1961 #if PG_VERSION_NUM < 110000
1962 
1963 		dynexpr->dtype = PLPGSQL_DTYPE_EXPR;
1964 		dynexpr->dno = -1;
1965 
1966 #endif
1967 
1968 #if PG_VERSION_NUM >= 140000
1969 
1970 		dynexpr->expr_rw_param = NULL;
1971 
1972 #else
1973 
1974 		dynexpr->rwparam = -1;
1975 
1976 #endif
1977 
1978 		dynexpr->query = dynquery;
1979 
1980 		dsp.args = params;
1981 		dsp.cstate = cstate;
1982 		dsp.use_params = false;
1983 
1984 		/*
1985 		 * When dynquery is not really constant, then there are
1986 		 * possible false alarms because we try to replace string
1987 		 * literal by parameter, so we can use it just for type
1988 		 * detection when check is ok.
1989 		 */
1990 		if (expr_is_const)
1991 		{
1992 			PG_TRY();
1993 			{
1994 				cstate->allow_mp = true;
1995 
1996 				plpgsql_check_expr_generic_with_parser_setup(cstate,
1997 													 dynexpr,
1998 													 (ParserSetupHook) dynsql_parser_setup,
1999 													 &dsp);
2000 
2001 				is_mp = cstate->has_mp;
2002 				cstate->has_mp = false;
2003 			}
2004 			PG_CATCH();
2005 			{
2006 				cstate->allow_mp = false;
2007 				cstate->has_mp = false;
2008 
2009 				PG_RE_THROW();
2010 			}
2011 			PG_END_TRY();
2012 		}
2013 		else
2014 		{
2015 			MemoryContext oldCxt;
2016 			ResourceOwner oldowner;
2017 
2018 			/*
2019 			 * When dynquery is not really constant, then there are
2020 			 * possible false alarms because we try to replace string
2021 			 * literal by parameter, so we can use it just for type
2022 			 * detection when check is ok.
2023 			 */
2024 
2025 			oldCxt = CurrentMemoryContext;
2026 
2027 			oldowner = CurrentResourceOwner;
2028 			BeginInternalSubTransaction(NULL);
2029 			MemoryContextSwitchTo(cstate->check_cxt);
2030 
2031 			PG_TRY();
2032 			{
2033 				cstate->allow_mp = true;
2034 
2035 				plpgsql_check_expr_generic_with_parser_setup(cstate,
2036 													 dynexpr,
2037 													 (ParserSetupHook) dynsql_parser_setup,
2038 													 &dsp);
2039 
2040 				is_mp = cstate->has_mp;
2041 				cstate->has_mp = false;
2042 
2043 				RollbackAndReleaseCurrentSubTransaction();
2044 				MemoryContextSwitchTo(oldCxt);
2045 				CurrentResourceOwner = oldowner;
2046 
2047 				SPI_restore_connection();
2048 			}
2049 			PG_CATCH();
2050 			{
2051 				is_ok = false;
2052 
2053 				cstate->allow_mp = false;
2054 				cstate->has_mp = false;
2055 
2056 				MemoryContextSwitchTo(oldCxt);
2057 				FlushErrorState();
2058 
2059 				RollbackAndReleaseCurrentSubTransaction();
2060 				MemoryContextSwitchTo(oldCxt);
2061 				CurrentResourceOwner = oldowner;
2062 			}
2063 			PG_END_TRY();
2064 		}
2065 
2066 		if (is_ok && expr_is_const && !is_mp && (!params || !dsp.use_params))
2067 		{
2068 
2069 			/* probably useless dynamic command */
2070 			plpgsql_check_put_error(cstate,
2071 									0, 0,
2072 									"immutable expression without parameters found",
2073 									"the EXECUTE command is not necessary probably",
2074 									"Don't use dynamic SQL when you can use static SQL.",
2075 									PLPGSQL_CHECK_WARNING_PERFORMANCE,
2076 									0, NULL, NULL);
2077 		}
2078 
2079 		if (is_ok && params && !dsp.use_params)
2080 		{
2081 			plpgsql_check_put_error(cstate,
2082 									0, 0,
2083 						  "values passed to EXECUTE statement by USING clause was not used",
2084 									NULL,
2085 									NULL,
2086 									PLPGSQL_CHECK_WARNING_OTHERS,
2087 									0, NULL, NULL);
2088 		}
2089 
2090 		if (is_ok && dynexpr->plan)
2091 		{
2092 			known_type_of_dynexpr = true;
2093 
2094 			if (stmt->cmd_type == PLPGSQL_STMT_RETURN_QUERY)
2095 			{
2096 				plpgsql_check_returned_expr(cstate, dynexpr, false);
2097 				cstate->found_return_query = true;
2098 			}
2099 			else if (into)
2100 			{
2101 
2102 #if PG_VERSION_NUM >= 110000
2103 
2104 				check_variable(cstate, target);
2105 				plpgsql_check_assignment_to_variable(cstate, dynexpr, target, -1);
2106 
2107 #else
2108 
2109 				plpgsql_check_row_or_rec(cstate, row, rec);
2110 				plpgsql_check_assignment(cstate, dynexpr, rec, row, -1);
2111 
2112 #endif
2113 
2114 			}
2115 		}
2116 
2117 		/* this is not real dynamic SQL statement */
2118 		if (!is_mp)
2119 			cstate->has_execute_stmt = prev_has_execute_stmt;
2120 	}
2121 
2122 	if (!expr_is_const)
2123 	{
2124 		/*
2125 		 * execute string is not constant (is not safe),
2126 		 * but we can check sanitize parameters.
2127 		 */
2128 		if (cstate->cinfo->security_warnings &&
2129 			plpgsql_check_is_sql_injection_vulnerable(cstate, query, expr_node, &loc))
2130 		{
2131 			if (loc != -1)
2132 				plpgsql_check_put_error(cstate,
2133 										0, 0,
2134 							"text type variable is not sanitized",
2135 							"The EXECUTE expression is SQL injection vulnerable.",
2136 							"Use quote_ident, quote_literal or format function to secure variable.",
2137 										PLPGSQL_CHECK_WARNING_SECURITY,
2138 										loc,
2139 										query->query,
2140 										NULL);
2141 			else
2142 				plpgsql_check_put_error(cstate,
2143 										0, 0,
2144 							"the expression is not SQL injection safe",
2145 							"Cannot ensure so dynamic EXECUTE statement is SQL injection secure.",
2146 							"Use quote_ident, quote_literal or format function to secure variable.",
2147 										PLPGSQL_CHECK_WARNING_SECURITY,
2148 										-1,
2149 										query->query,
2150 										NULL);
2151 		}
2152 
2153 		/* in this case we don't know number of output columns */
2154 		if (stmt->cmd_type == PLPGSQL_STMT_RETURN_QUERY &&
2155 			!known_type_of_dynexpr)
2156 		{
2157 			cstate->found_return_dyn_query = true;
2158 		}
2159 
2160 		/*
2161 		 * In this case, we don't know a result type, and we should
2162 		 * to raise warning about this situation.
2163 		 */
2164 		if (into && !known_type_of_dynexpr)
2165 		{
2166 
2167 #if PG_VERSION_NUM >= 110000
2168 
2169 			if (target->dtype == PLPGSQL_DTYPE_REC)
2170 				raise_unknown_rec_warning = true;
2171 
2172 #else
2173 
2174 			if (rec)
2175 				raise_unknown_rec_warning = true;
2176 
2177 #endif
2178 
2179 		}
2180 	}
2181 
2182 	/* recheck if target rec var has assigned tupdesc */
2183 	if (into)
2184 	{
2185 
2186 #if PG_VERSION_NUM >= 110000
2187 
2188 		check_variable(cstate, target);
2189 
2190 		if (raise_unknown_rec_warning ||
2191 			(target->dtype == PLPGSQL_DTYPE_REC &&
2192 			 !has_assigned_tupdesc(cstate, (PLpgSQL_rec *) target)))
2193 
2194 #else
2195 
2196 		plpgsql_check_row_or_rec(cstate, row, rec);
2197 
2198 		if (raise_unknown_rec_warning || (rec != NULL && !has_assigned_tupdesc(cstate, rec)))
2199 
2200 #endif
2201 
2202 		{
2203 
2204 #if PG_VERSION_NUM >= 110000
2205 
2206 			if (!bms_is_member(target->dno, cstate->typed_variables))
2207 
2208 #else
2209 
2210 			if (!bms_is_member(rec->dno, cstate->typed_variables))
2211 
2212 #endif
2213 
2214 				plpgsql_check_put_error(cstate,
2215 										0, 0,
2216 										"cannot determinate a result of dynamic SQL",
2217 										"There is a risk of related false alarms.",
2218 							  "Don't use dynamic SQL and record type together, when you would check function.",
2219 										PLPGSQL_CHECK_WARNING_OTHERS,
2220 										0, NULL, NULL);
2221 		}
2222 	}
2223 }
2224