Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pl_funcs.c - Misc functions 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_funcs.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 :
16 : #include "postgres.h"
17 :
18 : #include "plpgsql.h"
19 : #include "utils/memutils.h"
20 :
21 : /* ----------
22 : * Local variables for namespace handling
23 : *
24 : * The namespace structure actually forms a tree, of which only one linear
25 : * list or "chain" (from the youngest item to the root) is accessible from
26 : * any one plpgsql statement. During initial parsing of a function, ns_top
27 : * points to the youngest item accessible from the block currently being
28 : * parsed. We store the entire tree, however, since at runtime we will need
29 : * to access the chain that's relevant to any one statement.
30 : *
31 : * Block boundaries in the namespace chain are marked by PLPGSQL_NSTYPE_LABEL
32 : * items.
33 : * ----------
34 : */
35 : static PLpgSQL_nsitem *ns_top = NULL;
36 :
37 :
38 : /* ----------
39 : * plpgsql_ns_init Initialize namespace processing for a new function
40 : * ----------
41 : */
42 : void
43 9802 : plpgsql_ns_init(void)
44 : {
45 9802 : ns_top = NULL;
46 9802 : }
47 :
48 :
49 : /* ----------
50 : * plpgsql_ns_push Create a new namespace level
51 : * ----------
52 : */
53 : void
54 21770 : plpgsql_ns_push(const char *label, PLpgSQL_label_type label_type)
55 : {
56 21770 : if (label == NULL)
57 11754 : label = "";
58 21770 : plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, (int) label_type, label);
59 21770 : }
60 :
61 :
62 : /* ----------
63 : * plpgsql_ns_pop Pop entries back to (and including) the last label
64 : * ----------
65 : */
66 : void
67 11768 : plpgsql_ns_pop(void)
68 : {
69 : Assert(ns_top != NULL);
70 19782 : while (ns_top->itemtype != PLPGSQL_NSTYPE_LABEL)
71 8014 : ns_top = ns_top->prev;
72 11768 : ns_top = ns_top->prev;
73 11768 : }
74 :
75 :
76 : /* ----------
77 : * plpgsql_ns_top Fetch the current namespace chain end
78 : * ----------
79 : */
80 : PLpgSQL_nsitem *
81 99070 : plpgsql_ns_top(void)
82 : {
83 99070 : return ns_top;
84 : }
85 :
86 :
87 : /* ----------
88 : * plpgsql_ns_additem Add an item to the current namespace chain
89 : * ----------
90 : */
91 : void
92 95160 : plpgsql_ns_additem(PLpgSQL_nsitem_type itemtype, int itemno, const char *name)
93 : {
94 : PLpgSQL_nsitem *nse;
95 :
96 : Assert(name != NULL);
97 : /* first item added must be a label */
98 : Assert(ns_top != NULL || itemtype == PLPGSQL_NSTYPE_LABEL);
99 :
100 95160 : nse = palloc(offsetof(PLpgSQL_nsitem, name) + strlen(name) + 1);
101 95160 : nse->itemtype = itemtype;
102 95160 : nse->itemno = itemno;
103 95160 : nse->prev = ns_top;
104 95160 : strcpy(nse->name, name);
105 95160 : ns_top = nse;
106 95160 : }
107 :
108 :
109 : /* ----------
110 : * plpgsql_ns_lookup Lookup an identifier in the given namespace chain
111 : *
112 : * Note that this only searches for variables, not labels.
113 : *
114 : * If localmode is true, only the topmost block level is searched.
115 : *
116 : * name1 must be non-NULL. Pass NULL for name2 and/or name3 if parsing a name
117 : * with fewer than three components.
118 : *
119 : * If names_used isn't NULL, *names_used receives the number of names
120 : * matched: 0 if no match, 1 if name1 matched an unqualified variable name,
121 : * 2 if name1 and name2 matched a block label + variable name.
122 : *
123 : * Note that name3 is never directly matched to anything. However, if it
124 : * isn't NULL, we will disregard qualified matches to scalar variables.
125 : * Similarly, if name2 isn't NULL, we disregard unqualified matches to
126 : * scalar variables.
127 : * ----------
128 : */
129 : PLpgSQL_nsitem *
130 92724 : plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur, bool localmode,
131 : const char *name1, const char *name2, const char *name3,
132 : int *names_used)
133 : {
134 : /* Outer loop iterates once per block level in the namespace chain */
135 181064 : while (ns_cur != NULL)
136 : {
137 : PLpgSQL_nsitem *nsitem;
138 :
139 : /* Check this level for unqualified match to variable name */
140 162128 : for (nsitem = ns_cur;
141 605610 : nsitem->itemtype != PLPGSQL_NSTYPE_LABEL;
142 443482 : nsitem = nsitem->prev)
143 : {
144 502226 : if (strcmp(nsitem->name, name1) == 0)
145 : {
146 58744 : if (name2 == NULL ||
147 12742 : nsitem->itemtype != PLPGSQL_NSTYPE_VAR)
148 : {
149 58744 : if (names_used)
150 41436 : *names_used = 1;
151 58744 : return nsitem;
152 : }
153 : }
154 : }
155 :
156 : /* Check this level for qualified match to variable name */
157 103384 : if (name2 != NULL &&
158 14382 : strcmp(nsitem->name, name1) == 0)
159 : {
160 146 : for (nsitem = ns_cur;
161 250 : nsitem->itemtype != PLPGSQL_NSTYPE_LABEL;
162 104 : nsitem = nsitem->prev)
163 : {
164 248 : if (strcmp(nsitem->name, name2) == 0)
165 : {
166 144 : if (name3 == NULL ||
167 66 : nsitem->itemtype != PLPGSQL_NSTYPE_VAR)
168 : {
169 144 : if (names_used)
170 144 : *names_used = 2;
171 144 : return nsitem;
172 : }
173 : }
174 : }
175 : }
176 :
177 103240 : if (localmode)
178 14900 : break; /* do not look into upper levels */
179 :
180 88340 : ns_cur = nsitem->prev;
181 : }
182 :
183 : /* This is just to suppress possibly-uninitialized-variable warnings */
184 33836 : if (names_used)
185 5256 : *names_used = 0;
186 33836 : return NULL; /* No match found */
187 : }
188 :
189 :
190 : /* ----------
191 : * plpgsql_ns_lookup_label Lookup a label in the given namespace chain
192 : * ----------
193 : */
194 : PLpgSQL_nsitem *
195 32 : plpgsql_ns_lookup_label(PLpgSQL_nsitem *ns_cur, const char *name)
196 : {
197 86 : while (ns_cur != NULL)
198 : {
199 82 : if (ns_cur->itemtype == PLPGSQL_NSTYPE_LABEL &&
200 68 : strcmp(ns_cur->name, name) == 0)
201 28 : return ns_cur;
202 54 : ns_cur = ns_cur->prev;
203 : }
204 :
205 4 : return NULL; /* label not found */
206 : }
207 :
208 :
209 : /* ----------
210 : * plpgsql_ns_find_nearest_loop Find innermost loop label in namespace chain
211 : * ----------
212 : */
213 : PLpgSQL_nsitem *
214 198 : plpgsql_ns_find_nearest_loop(PLpgSQL_nsitem *ns_cur)
215 : {
216 248 : while (ns_cur != NULL)
217 : {
218 244 : if (ns_cur->itemtype == PLPGSQL_NSTYPE_LABEL &&
219 214 : ns_cur->itemno == PLPGSQL_LABEL_LOOP)
220 194 : return ns_cur;
221 50 : ns_cur = ns_cur->prev;
222 : }
223 :
224 4 : return NULL; /* no loop found */
225 : }
226 :
227 :
228 : /*
229 : * Statement type as a string, for use in error messages etc.
230 : */
231 : const char *
232 22780 : plpgsql_stmt_typename(PLpgSQL_stmt *stmt)
233 : {
234 22780 : switch (stmt->cmd_type)
235 : {
236 0 : case PLPGSQL_STMT_BLOCK:
237 0 : return _("statement block");
238 560 : case PLPGSQL_STMT_ASSIGN:
239 560 : return _("assignment");
240 0 : case PLPGSQL_STMT_IF:
241 0 : return "IF";
242 6 : case PLPGSQL_STMT_CASE:
243 6 : return "CASE";
244 0 : case PLPGSQL_STMT_LOOP:
245 0 : return "LOOP";
246 0 : case PLPGSQL_STMT_WHILE:
247 0 : return "WHILE";
248 6 : case PLPGSQL_STMT_FORI:
249 6 : return _("FOR with integer loop variable");
250 16 : case PLPGSQL_STMT_FORS:
251 16 : return _("FOR over SELECT rows");
252 0 : case PLPGSQL_STMT_FORC:
253 0 : return _("FOR over cursor");
254 18 : case PLPGSQL_STMT_FOREACH_A:
255 18 : return _("FOREACH over array");
256 0 : case PLPGSQL_STMT_EXIT:
257 0 : return ((PLpgSQL_stmt_exit *) stmt)->is_exit ? "EXIT" : "CONTINUE";
258 138 : case PLPGSQL_STMT_RETURN:
259 138 : return "RETURN";
260 4 : case PLPGSQL_STMT_RETURN_NEXT:
261 4 : return "RETURN NEXT";
262 18 : case PLPGSQL_STMT_RETURN_QUERY:
263 18 : return "RETURN QUERY";
264 15446 : case PLPGSQL_STMT_RAISE:
265 15446 : return "RAISE";
266 24 : case PLPGSQL_STMT_ASSERT:
267 24 : return "ASSERT";
268 4476 : case PLPGSQL_STMT_EXECSQL:
269 4476 : return _("SQL statement");
270 394 : case PLPGSQL_STMT_DYNEXECUTE:
271 394 : return "EXECUTE";
272 70 : case PLPGSQL_STMT_DYNFORS:
273 70 : return _("FOR over EXECUTE statement");
274 54 : case PLPGSQL_STMT_GETDIAG:
275 54 : return ((PLpgSQL_stmt_getdiag *) stmt)->is_stacked ?
276 54 : "GET STACKED DIAGNOSTICS" : "GET DIAGNOSTICS";
277 12 : case PLPGSQL_STMT_OPEN:
278 12 : return "OPEN";
279 6 : case PLPGSQL_STMT_FETCH:
280 6 : return ((PLpgSQL_stmt_fetch *) stmt)->is_move ? "MOVE" : "FETCH";
281 0 : case PLPGSQL_STMT_CLOSE:
282 0 : return "CLOSE";
283 1426 : case PLPGSQL_STMT_PERFORM:
284 1426 : return "PERFORM";
285 78 : case PLPGSQL_STMT_CALL:
286 78 : return ((PLpgSQL_stmt_call *) stmt)->is_call ? "CALL" : "DO";
287 22 : case PLPGSQL_STMT_COMMIT:
288 22 : return "COMMIT";
289 6 : case PLPGSQL_STMT_ROLLBACK:
290 6 : return "ROLLBACK";
291 : }
292 :
293 0 : return "unknown";
294 : }
295 :
296 : /*
297 : * GET DIAGNOSTICS item name as a string, for use in error messages etc.
298 : */
299 : const char *
300 0 : plpgsql_getdiag_kindname(PLpgSQL_getdiag_kind kind)
301 : {
302 0 : switch (kind)
303 : {
304 0 : case PLPGSQL_GETDIAG_ROW_COUNT:
305 0 : return "ROW_COUNT";
306 0 : case PLPGSQL_GETDIAG_ROUTINE_OID:
307 0 : return "PG_ROUTINE_OID";
308 0 : case PLPGSQL_GETDIAG_CONTEXT:
309 0 : return "PG_CONTEXT";
310 0 : case PLPGSQL_GETDIAG_ERROR_CONTEXT:
311 0 : return "PG_EXCEPTION_CONTEXT";
312 0 : case PLPGSQL_GETDIAG_ERROR_DETAIL:
313 0 : return "PG_EXCEPTION_DETAIL";
314 0 : case PLPGSQL_GETDIAG_ERROR_HINT:
315 0 : return "PG_EXCEPTION_HINT";
316 0 : case PLPGSQL_GETDIAG_RETURNED_SQLSTATE:
317 0 : return "RETURNED_SQLSTATE";
318 0 : case PLPGSQL_GETDIAG_COLUMN_NAME:
319 0 : return "COLUMN_NAME";
320 0 : case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
321 0 : return "CONSTRAINT_NAME";
322 0 : case PLPGSQL_GETDIAG_DATATYPE_NAME:
323 0 : return "PG_DATATYPE_NAME";
324 0 : case PLPGSQL_GETDIAG_MESSAGE_TEXT:
325 0 : return "MESSAGE_TEXT";
326 0 : case PLPGSQL_GETDIAG_TABLE_NAME:
327 0 : return "TABLE_NAME";
328 0 : case PLPGSQL_GETDIAG_SCHEMA_NAME:
329 0 : return "SCHEMA_NAME";
330 : }
331 :
332 0 : return "unknown";
333 : }
334 :
335 :
336 : /**********************************************************************
337 : * Support for recursing through a PL/pgSQL statement tree
338 : *
339 : * The point of this code is to encapsulate knowledge of where the
340 : * sub-statements and expressions are in a statement tree, avoiding
341 : * duplication of code. The caller supplies two callbacks, one to
342 : * be invoked on statements and one to be invoked on expressions.
343 : * (The recursion should be started by invoking the statement callback
344 : * on function->action.) The statement callback should do any
345 : * statement-type-specific action it needs, then recurse by calling
346 : * plpgsql_statement_tree_walker(). The expression callback can be a
347 : * no-op if no per-expression behavior is needed.
348 : **********************************************************************/
349 : typedef void (*plpgsql_stmt_walker_callback) (PLpgSQL_stmt *stmt,
350 : void *context);
351 : typedef void (*plpgsql_expr_walker_callback) (PLpgSQL_expr *expr,
352 : void *context);
353 :
354 : /*
355 : * As in nodeFuncs.h, we respectfully decline to support the C standard's
356 : * position that a pointer to struct is incompatible with "void *". Instead,
357 : * silence related compiler warnings using casts in this macro wrapper.
358 : */
359 : #define plpgsql_statement_tree_walker(s, sw, ew, c) \
360 : plpgsql_statement_tree_walker_impl(s, (plpgsql_stmt_walker_callback) (sw), \
361 : (plpgsql_expr_walker_callback) (ew), c)
362 :
363 : static void
364 14154 : plpgsql_statement_tree_walker_impl(PLpgSQL_stmt *stmt,
365 : plpgsql_stmt_walker_callback stmt_callback,
366 : plpgsql_expr_walker_callback expr_callback,
367 : void *context)
368 : {
369 : #define S_WALK(st) stmt_callback(st, context)
370 : #define E_WALK(ex) expr_callback(ex, context)
371 : #define S_LIST_WALK(lst) foreach_ptr(PLpgSQL_stmt, st, lst) S_WALK(st)
372 : #define E_LIST_WALK(lst) foreach_ptr(PLpgSQL_expr, ex, lst) E_WALK(ex)
373 :
374 14154 : switch (stmt->cmd_type)
375 : {
376 3186 : case PLPGSQL_STMT_BLOCK:
377 : {
378 3186 : PLpgSQL_stmt_block *bstmt = (PLpgSQL_stmt_block *) stmt;
379 :
380 14556 : S_LIST_WALK(bstmt->body);
381 3186 : if (bstmt->exceptions)
382 : {
383 1770 : foreach_ptr(PLpgSQL_exception, exc, bstmt->exceptions->exc_list)
384 : {
385 : /* conditions list has no interesting sub-structure */
386 1750 : S_LIST_WALK(exc->action);
387 : }
388 : }
389 3186 : break;
390 : }
391 996 : case PLPGSQL_STMT_ASSIGN:
392 : {
393 996 : PLpgSQL_stmt_assign *astmt = (PLpgSQL_stmt_assign *) stmt;
394 :
395 996 : E_WALK(astmt->expr);
396 996 : break;
397 : }
398 356 : case PLPGSQL_STMT_IF:
399 : {
400 356 : PLpgSQL_stmt_if *ifstmt = (PLpgSQL_stmt_if *) stmt;
401 :
402 356 : E_WALK(ifstmt->cond);
403 1302 : S_LIST_WALK(ifstmt->then_body);
404 712 : foreach_ptr(PLpgSQL_if_elsif, elif, ifstmt->elsif_list)
405 : {
406 0 : E_WALK(elif->cond);
407 0 : S_LIST_WALK(elif->stmts);
408 : }
409 862 : S_LIST_WALK(ifstmt->else_body);
410 356 : break;
411 : }
412 2 : case PLPGSQL_STMT_CASE:
413 : {
414 2 : PLpgSQL_stmt_case *cstmt = (PLpgSQL_stmt_case *) stmt;
415 :
416 2 : E_WALK(cstmt->t_expr);
417 14 : foreach_ptr(PLpgSQL_case_when, cwt, cstmt->case_when_list)
418 : {
419 10 : E_WALK(cwt->expr);
420 30 : S_LIST_WALK(cwt->stmts);
421 : }
422 4 : S_LIST_WALK(cstmt->else_stmts);
423 2 : break;
424 : }
425 46 : case PLPGSQL_STMT_LOOP:
426 : {
427 46 : PLpgSQL_stmt_loop *lstmt = (PLpgSQL_stmt_loop *) stmt;
428 :
429 210 : S_LIST_WALK(lstmt->body);
430 46 : break;
431 : }
432 56 : case PLPGSQL_STMT_WHILE:
433 : {
434 56 : PLpgSQL_stmt_while *wstmt = (PLpgSQL_stmt_while *) stmt;
435 :
436 56 : E_WALK(wstmt->cond);
437 238 : S_LIST_WALK(wstmt->body);
438 56 : break;
439 : }
440 582 : case PLPGSQL_STMT_FORI:
441 : {
442 582 : PLpgSQL_stmt_fori *fori = (PLpgSQL_stmt_fori *) stmt;
443 :
444 582 : E_WALK(fori->lower);
445 582 : E_WALK(fori->upper);
446 582 : E_WALK(fori->step);
447 2258 : S_LIST_WALK(fori->body);
448 582 : break;
449 : }
450 144 : case PLPGSQL_STMT_FORS:
451 : {
452 144 : PLpgSQL_stmt_fors *fors = (PLpgSQL_stmt_fors *) stmt;
453 :
454 814 : S_LIST_WALK(fors->body);
455 144 : E_WALK(fors->query);
456 144 : break;
457 : }
458 50 : case PLPGSQL_STMT_FORC:
459 : {
460 50 : PLpgSQL_stmt_forc *forc = (PLpgSQL_stmt_forc *) stmt;
461 :
462 158 : S_LIST_WALK(forc->body);
463 50 : E_WALK(forc->argquery);
464 50 : break;
465 : }
466 48 : case PLPGSQL_STMT_FOREACH_A:
467 : {
468 48 : PLpgSQL_stmt_foreach_a *fstmt = (PLpgSQL_stmt_foreach_a *) stmt;
469 :
470 48 : E_WALK(fstmt->expr);
471 144 : S_LIST_WALK(fstmt->body);
472 48 : break;
473 : }
474 78 : case PLPGSQL_STMT_EXIT:
475 : {
476 78 : PLpgSQL_stmt_exit *estmt = (PLpgSQL_stmt_exit *) stmt;
477 :
478 78 : E_WALK(estmt->cond);
479 78 : break;
480 : }
481 2788 : case PLPGSQL_STMT_RETURN:
482 : {
483 2788 : PLpgSQL_stmt_return *rstmt = (PLpgSQL_stmt_return *) stmt;
484 :
485 2788 : E_WALK(rstmt->expr);
486 2788 : break;
487 : }
488 62 : case PLPGSQL_STMT_RETURN_NEXT:
489 : {
490 62 : PLpgSQL_stmt_return_next *rstmt = (PLpgSQL_stmt_return_next *) stmt;
491 :
492 62 : E_WALK(rstmt->expr);
493 62 : break;
494 : }
495 38 : case PLPGSQL_STMT_RETURN_QUERY:
496 : {
497 38 : PLpgSQL_stmt_return_query *rstmt = (PLpgSQL_stmt_return_query *) stmt;
498 :
499 38 : E_WALK(rstmt->query);
500 38 : E_WALK(rstmt->dynquery);
501 76 : E_LIST_WALK(rstmt->params);
502 38 : break;
503 : }
504 1808 : case PLPGSQL_STMT_RAISE:
505 : {
506 1808 : PLpgSQL_stmt_raise *rstmt = (PLpgSQL_stmt_raise *) stmt;
507 :
508 5742 : E_LIST_WALK(rstmt->params);
509 3868 : foreach_ptr(PLpgSQL_raise_option, opt, rstmt->options)
510 : {
511 252 : E_WALK(opt->expr);
512 : }
513 1808 : break;
514 : }
515 42 : case PLPGSQL_STMT_ASSERT:
516 : {
517 42 : PLpgSQL_stmt_assert *astmt = (PLpgSQL_stmt_assert *) stmt;
518 :
519 42 : E_WALK(astmt->cond);
520 42 : E_WALK(astmt->message);
521 42 : break;
522 : }
523 1952 : case PLPGSQL_STMT_EXECSQL:
524 : {
525 1952 : PLpgSQL_stmt_execsql *xstmt = (PLpgSQL_stmt_execsql *) stmt;
526 :
527 1952 : E_WALK(xstmt->sqlstmt);
528 1952 : break;
529 : }
530 480 : case PLPGSQL_STMT_DYNEXECUTE:
531 : {
532 480 : PLpgSQL_stmt_dynexecute *dstmt = (PLpgSQL_stmt_dynexecute *) stmt;
533 :
534 480 : E_WALK(dstmt->query);
535 978 : E_LIST_WALK(dstmt->params);
536 480 : break;
537 : }
538 78 : case PLPGSQL_STMT_DYNFORS:
539 : {
540 78 : PLpgSQL_stmt_dynfors *dstmt = (PLpgSQL_stmt_dynfors *) stmt;
541 :
542 234 : S_LIST_WALK(dstmt->body);
543 78 : E_WALK(dstmt->query);
544 156 : E_LIST_WALK(dstmt->params);
545 78 : break;
546 : }
547 110 : case PLPGSQL_STMT_GETDIAG:
548 : {
549 : /* no interesting sub-structure */
550 110 : break;
551 : }
552 44 : case PLPGSQL_STMT_OPEN:
553 : {
554 44 : PLpgSQL_stmt_open *ostmt = (PLpgSQL_stmt_open *) stmt;
555 :
556 44 : E_WALK(ostmt->argquery);
557 44 : E_WALK(ostmt->query);
558 44 : E_WALK(ostmt->dynquery);
559 88 : E_LIST_WALK(ostmt->params);
560 44 : break;
561 : }
562 80 : case PLPGSQL_STMT_FETCH:
563 : {
564 80 : PLpgSQL_stmt_fetch *fstmt = (PLpgSQL_stmt_fetch *) stmt;
565 :
566 80 : E_WALK(fstmt->expr);
567 80 : break;
568 : }
569 36 : case PLPGSQL_STMT_CLOSE:
570 : {
571 : /* no interesting sub-structure */
572 36 : break;
573 : }
574 910 : case PLPGSQL_STMT_PERFORM:
575 : {
576 910 : PLpgSQL_stmt_perform *pstmt = (PLpgSQL_stmt_perform *) stmt;
577 :
578 910 : E_WALK(pstmt->expr);
579 910 : break;
580 : }
581 88 : case PLPGSQL_STMT_CALL:
582 : {
583 88 : PLpgSQL_stmt_call *cstmt = (PLpgSQL_stmt_call *) stmt;
584 :
585 88 : E_WALK(cstmt->expr);
586 88 : break;
587 : }
588 94 : case PLPGSQL_STMT_COMMIT:
589 : case PLPGSQL_STMT_ROLLBACK:
590 : {
591 : /* no interesting sub-structure */
592 94 : break;
593 : }
594 0 : default:
595 0 : elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
596 : break;
597 : }
598 14154 : }
599 :
600 :
601 : /**********************************************************************
602 : * Mark assignment source expressions that have local target variables,
603 : * that is, the target variable is declared within the exception block
604 : * most closely containing the assignment itself. (Such target variables
605 : * need not be preserved if the assignment's source expression raises an
606 : * error, since the variable will no longer be accessible afterwards.
607 : * Detecting this allows better optimization.)
608 : *
609 : * This code need not be called if the plpgsql function contains no exception
610 : * blocks, because mark_expr_as_assignment_source will have set all the flags
611 : * to true already. Also, we need not reconsider default-value expressions
612 : * for variables, because variable declarations are necessarily within the
613 : * nearest exception block. (In DECLARE ... BEGIN ... EXCEPTION ... END, the
614 : * variable initializations are done before entering the exception scope.)
615 : *
616 : * Within the recursion, local_dnos is a Bitmapset of dnos of variables
617 : * known to be declared within the current exception level.
618 : **********************************************************************/
619 : static void mark_stmt(PLpgSQL_stmt *stmt, Bitmapset *local_dnos);
620 : static void mark_expr(PLpgSQL_expr *expr, Bitmapset *local_dnos);
621 :
622 : static void
623 2556 : mark_stmt(PLpgSQL_stmt *stmt, Bitmapset *local_dnos)
624 : {
625 2556 : if (stmt == NULL)
626 0 : return;
627 2556 : if (stmt->cmd_type == PLPGSQL_STMT_BLOCK)
628 : {
629 848 : PLpgSQL_stmt_block *block = (PLpgSQL_stmt_block *) stmt;
630 :
631 848 : if (block->exceptions)
632 : {
633 : /*
634 : * The block creates a new exception scope, so variables declared
635 : * at outer levels are nonlocal. For that matter, so are any
636 : * variables declared in the block's DECLARE section. Hence, we
637 : * must pass down empty local_dnos.
638 : */
639 460 : plpgsql_statement_tree_walker(stmt, mark_stmt, mark_expr, NULL);
640 : }
641 : else
642 : {
643 : /*
644 : * Otherwise, the block does not create a new exception scope, and
645 : * any variables it declares can also be considered local within
646 : * it. Note that only initializable datum types (VAR, REC) are
647 : * included in initvarnos; but that's sufficient for our purposes.
648 : */
649 388 : local_dnos = bms_copy(local_dnos);
650 494 : for (int i = 0; i < block->n_initvars; i++)
651 106 : local_dnos = bms_add_member(local_dnos, block->initvarnos[i]);
652 388 : plpgsql_statement_tree_walker(stmt, mark_stmt, mark_expr,
653 : local_dnos);
654 388 : bms_free(local_dnos);
655 : }
656 : }
657 : else
658 1708 : plpgsql_statement_tree_walker(stmt, mark_stmt, mark_expr, local_dnos);
659 : }
660 :
661 : static void
662 1774 : mark_expr(PLpgSQL_expr *expr, Bitmapset *local_dnos)
663 : {
664 : /*
665 : * If this expression has an assignment target, check whether the target
666 : * is local, and mark the expression accordingly.
667 : */
668 1774 : if (expr && expr->target_param >= 0)
669 122 : expr->target_is_local = bms_is_member(expr->target_param, local_dnos);
670 1774 : }
671 :
672 : void
673 442 : plpgsql_mark_local_assignment_targets(PLpgSQL_function *func)
674 : {
675 : Bitmapset *local_dnos;
676 :
677 : /* Function parameters can be treated as local targets at outer level */
678 442 : local_dnos = NULL;
679 580 : for (int i = 0; i < func->fn_nargs; i++)
680 138 : local_dnos = bms_add_member(local_dnos, func->fn_argvarnos[i]);
681 442 : mark_stmt((PLpgSQL_stmt *) func->action, local_dnos);
682 442 : bms_free(local_dnos);
683 442 : }
684 :
685 :
686 : /**********************************************************************
687 : * Release memory when a PL/pgSQL function is no longer needed
688 : *
689 : * This code only needs to deal with cleaning up PLpgSQL_expr nodes,
690 : * which may contain references to saved SPI Plans that must be freed.
691 : * The function tree itself, along with subsidiary data, is freed in
692 : * one swoop by freeing the function's permanent memory context.
693 : **********************************************************************/
694 : static void free_stmt(PLpgSQL_stmt *stmt, void *context);
695 : static void free_expr(PLpgSQL_expr *expr, void *context);
696 :
697 : static void
698 11598 : free_stmt(PLpgSQL_stmt *stmt, void *context)
699 : {
700 11598 : if (stmt == NULL)
701 0 : return;
702 11598 : plpgsql_statement_tree_walker(stmt, free_stmt, free_expr, NULL);
703 : }
704 :
705 : static void
706 23164 : free_expr(PLpgSQL_expr *expr, void *context)
707 : {
708 23164 : if (expr && expr->plan)
709 : {
710 7256 : SPI_freeplan(expr->plan);
711 7256 : expr->plan = NULL;
712 : }
713 23164 : }
714 :
715 : void
716 2176 : plpgsql_free_function_memory(PLpgSQL_function *func)
717 : {
718 : int i;
719 :
720 : /* Better not call this on an in-use function */
721 : Assert(func->cfunc.use_count == 0);
722 :
723 : /* Release plans associated with variable declarations */
724 10022 : for (i = 0; i < func->ndatums; i++)
725 : {
726 7846 : PLpgSQL_datum *d = func->datums[i];
727 :
728 7846 : switch (d->dtype)
729 : {
730 5754 : case PLPGSQL_DTYPE_VAR:
731 : case PLPGSQL_DTYPE_PROMISE:
732 : {
733 5754 : PLpgSQL_var *var = (PLpgSQL_var *) d;
734 :
735 5754 : free_expr(var->default_val, NULL);
736 5754 : free_expr(var->cursor_explicit_expr, NULL);
737 : }
738 5754 : break;
739 346 : case PLPGSQL_DTYPE_ROW:
740 346 : break;
741 818 : case PLPGSQL_DTYPE_REC:
742 : {
743 818 : PLpgSQL_rec *rec = (PLpgSQL_rec *) d;
744 :
745 818 : free_expr(rec->default_val, NULL);
746 : }
747 818 : break;
748 928 : case PLPGSQL_DTYPE_RECFIELD:
749 928 : break;
750 0 : default:
751 0 : elog(ERROR, "unrecognized data type: %d", d->dtype);
752 : }
753 : }
754 2176 : func->ndatums = 0;
755 :
756 : /* Release plans in statement tree */
757 2176 : free_stmt((PLpgSQL_stmt *) func->action, NULL);
758 2176 : func->action = NULL;
759 :
760 : /*
761 : * And finally, release all memory except the PLpgSQL_function struct
762 : * itself (which has to be kept around because there may be multiple
763 : * fn_extra pointers to it).
764 : */
765 2176 : if (func->fn_cxt)
766 2176 : MemoryContextDelete(func->fn_cxt);
767 2176 : func->fn_cxt = NULL;
768 2176 : }
769 :
770 : /* Deletion callback used by funccache.c */
771 : void
772 708 : plpgsql_delete_callback(CachedFunction *cfunc)
773 : {
774 708 : plpgsql_free_function_memory((PLpgSQL_function *) cfunc);
775 708 : }
776 :
777 :
778 : /**********************************************************************
779 : * Debug functions for analyzing the compiled code
780 : *
781 : * Sadly, there doesn't seem to be any way to let plpgsql_statement_tree_walker
782 : * bear some of the burden for this.
783 : **********************************************************************/
784 : static int dump_indent;
785 :
786 : static void dump_ind(void);
787 : static void dump_stmt(PLpgSQL_stmt *stmt);
788 : static void dump_block(PLpgSQL_stmt_block *block);
789 : static void dump_assign(PLpgSQL_stmt_assign *stmt);
790 : static void dump_if(PLpgSQL_stmt_if *stmt);
791 : static void dump_case(PLpgSQL_stmt_case *stmt);
792 : static void dump_loop(PLpgSQL_stmt_loop *stmt);
793 : static void dump_while(PLpgSQL_stmt_while *stmt);
794 : static void dump_fori(PLpgSQL_stmt_fori *stmt);
795 : static void dump_fors(PLpgSQL_stmt_fors *stmt);
796 : static void dump_forc(PLpgSQL_stmt_forc *stmt);
797 : static void dump_foreach_a(PLpgSQL_stmt_foreach_a *stmt);
798 : static void dump_exit(PLpgSQL_stmt_exit *stmt);
799 : static void dump_return(PLpgSQL_stmt_return *stmt);
800 : static void dump_return_next(PLpgSQL_stmt_return_next *stmt);
801 : static void dump_return_query(PLpgSQL_stmt_return_query *stmt);
802 : static void dump_raise(PLpgSQL_stmt_raise *stmt);
803 : static void dump_assert(PLpgSQL_stmt_assert *stmt);
804 : static void dump_execsql(PLpgSQL_stmt_execsql *stmt);
805 : static void dump_dynexecute(PLpgSQL_stmt_dynexecute *stmt);
806 : static void dump_dynfors(PLpgSQL_stmt_dynfors *stmt);
807 : static void dump_getdiag(PLpgSQL_stmt_getdiag *stmt);
808 : static void dump_open(PLpgSQL_stmt_open *stmt);
809 : static void dump_fetch(PLpgSQL_stmt_fetch *stmt);
810 : static void dump_cursor_direction(PLpgSQL_stmt_fetch *stmt);
811 : static void dump_close(PLpgSQL_stmt_close *stmt);
812 : static void dump_perform(PLpgSQL_stmt_perform *stmt);
813 : static void dump_call(PLpgSQL_stmt_call *stmt);
814 : static void dump_commit(PLpgSQL_stmt_commit *stmt);
815 : static void dump_rollback(PLpgSQL_stmt_rollback *stmt);
816 : static void dump_expr(PLpgSQL_expr *expr);
817 :
818 :
819 : static void
820 0 : dump_ind(void)
821 : {
822 : int i;
823 :
824 0 : for (i = 0; i < dump_indent; i++)
825 0 : printf(" ");
826 0 : }
827 :
828 : static void
829 0 : dump_stmt(PLpgSQL_stmt *stmt)
830 : {
831 0 : printf("%3d:", stmt->lineno);
832 0 : switch (stmt->cmd_type)
833 : {
834 0 : case PLPGSQL_STMT_BLOCK:
835 0 : dump_block((PLpgSQL_stmt_block *) stmt);
836 0 : break;
837 0 : case PLPGSQL_STMT_ASSIGN:
838 0 : dump_assign((PLpgSQL_stmt_assign *) stmt);
839 0 : break;
840 0 : case PLPGSQL_STMT_IF:
841 0 : dump_if((PLpgSQL_stmt_if *) stmt);
842 0 : break;
843 0 : case PLPGSQL_STMT_CASE:
844 0 : dump_case((PLpgSQL_stmt_case *) stmt);
845 0 : break;
846 0 : case PLPGSQL_STMT_LOOP:
847 0 : dump_loop((PLpgSQL_stmt_loop *) stmt);
848 0 : break;
849 0 : case PLPGSQL_STMT_WHILE:
850 0 : dump_while((PLpgSQL_stmt_while *) stmt);
851 0 : break;
852 0 : case PLPGSQL_STMT_FORI:
853 0 : dump_fori((PLpgSQL_stmt_fori *) stmt);
854 0 : break;
855 0 : case PLPGSQL_STMT_FORS:
856 0 : dump_fors((PLpgSQL_stmt_fors *) stmt);
857 0 : break;
858 0 : case PLPGSQL_STMT_FORC:
859 0 : dump_forc((PLpgSQL_stmt_forc *) stmt);
860 0 : break;
861 0 : case PLPGSQL_STMT_FOREACH_A:
862 0 : dump_foreach_a((PLpgSQL_stmt_foreach_a *) stmt);
863 0 : break;
864 0 : case PLPGSQL_STMT_EXIT:
865 0 : dump_exit((PLpgSQL_stmt_exit *) stmt);
866 0 : break;
867 0 : case PLPGSQL_STMT_RETURN:
868 0 : dump_return((PLpgSQL_stmt_return *) stmt);
869 0 : break;
870 0 : case PLPGSQL_STMT_RETURN_NEXT:
871 0 : dump_return_next((PLpgSQL_stmt_return_next *) stmt);
872 0 : break;
873 0 : case PLPGSQL_STMT_RETURN_QUERY:
874 0 : dump_return_query((PLpgSQL_stmt_return_query *) stmt);
875 0 : break;
876 0 : case PLPGSQL_STMT_RAISE:
877 0 : dump_raise((PLpgSQL_stmt_raise *) stmt);
878 0 : break;
879 0 : case PLPGSQL_STMT_ASSERT:
880 0 : dump_assert((PLpgSQL_stmt_assert *) stmt);
881 0 : break;
882 0 : case PLPGSQL_STMT_EXECSQL:
883 0 : dump_execsql((PLpgSQL_stmt_execsql *) stmt);
884 0 : break;
885 0 : case PLPGSQL_STMT_DYNEXECUTE:
886 0 : dump_dynexecute((PLpgSQL_stmt_dynexecute *) stmt);
887 0 : break;
888 0 : case PLPGSQL_STMT_DYNFORS:
889 0 : dump_dynfors((PLpgSQL_stmt_dynfors *) stmt);
890 0 : break;
891 0 : case PLPGSQL_STMT_GETDIAG:
892 0 : dump_getdiag((PLpgSQL_stmt_getdiag *) stmt);
893 0 : break;
894 0 : case PLPGSQL_STMT_OPEN:
895 0 : dump_open((PLpgSQL_stmt_open *) stmt);
896 0 : break;
897 0 : case PLPGSQL_STMT_FETCH:
898 0 : dump_fetch((PLpgSQL_stmt_fetch *) stmt);
899 0 : break;
900 0 : case PLPGSQL_STMT_CLOSE:
901 0 : dump_close((PLpgSQL_stmt_close *) stmt);
902 0 : break;
903 0 : case PLPGSQL_STMT_PERFORM:
904 0 : dump_perform((PLpgSQL_stmt_perform *) stmt);
905 0 : break;
906 0 : case PLPGSQL_STMT_CALL:
907 0 : dump_call((PLpgSQL_stmt_call *) stmt);
908 0 : break;
909 0 : case PLPGSQL_STMT_COMMIT:
910 0 : dump_commit((PLpgSQL_stmt_commit *) stmt);
911 0 : break;
912 0 : case PLPGSQL_STMT_ROLLBACK:
913 0 : dump_rollback((PLpgSQL_stmt_rollback *) stmt);
914 0 : break;
915 0 : default:
916 0 : elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
917 : break;
918 : }
919 0 : }
920 :
921 : static void
922 0 : dump_stmts(List *stmts)
923 : {
924 : ListCell *s;
925 :
926 0 : dump_indent += 2;
927 0 : foreach(s, stmts)
928 0 : dump_stmt((PLpgSQL_stmt *) lfirst(s));
929 0 : dump_indent -= 2;
930 0 : }
931 :
932 : static void
933 0 : dump_block(PLpgSQL_stmt_block *block)
934 : {
935 : char *name;
936 :
937 0 : if (block->label == NULL)
938 0 : name = "*unnamed*";
939 : else
940 0 : name = block->label;
941 :
942 0 : dump_ind();
943 0 : printf("BLOCK <<%s>>\n", name);
944 :
945 0 : dump_stmts(block->body);
946 :
947 0 : if (block->exceptions)
948 : {
949 : ListCell *e;
950 :
951 0 : foreach(e, block->exceptions->exc_list)
952 : {
953 0 : PLpgSQL_exception *exc = (PLpgSQL_exception *) lfirst(e);
954 : PLpgSQL_condition *cond;
955 :
956 0 : dump_ind();
957 0 : printf(" EXCEPTION WHEN ");
958 0 : for (cond = exc->conditions; cond; cond = cond->next)
959 : {
960 0 : if (cond != exc->conditions)
961 0 : printf(" OR ");
962 0 : printf("%s", cond->condname);
963 : }
964 0 : printf(" THEN\n");
965 0 : dump_stmts(exc->action);
966 : }
967 : }
968 :
969 0 : dump_ind();
970 0 : printf(" END -- %s\n", name);
971 0 : }
972 :
973 : static void
974 0 : dump_assign(PLpgSQL_stmt_assign *stmt)
975 : {
976 0 : dump_ind();
977 0 : printf("ASSIGN var %d := ", stmt->varno);
978 0 : dump_expr(stmt->expr);
979 0 : printf("\n");
980 0 : }
981 :
982 : static void
983 0 : dump_if(PLpgSQL_stmt_if *stmt)
984 : {
985 : ListCell *l;
986 :
987 0 : dump_ind();
988 0 : printf("IF ");
989 0 : dump_expr(stmt->cond);
990 0 : printf(" THEN\n");
991 0 : dump_stmts(stmt->then_body);
992 0 : foreach(l, stmt->elsif_list)
993 : {
994 0 : PLpgSQL_if_elsif *elif = (PLpgSQL_if_elsif *) lfirst(l);
995 :
996 0 : dump_ind();
997 0 : printf(" ELSIF ");
998 0 : dump_expr(elif->cond);
999 0 : printf(" THEN\n");
1000 0 : dump_stmts(elif->stmts);
1001 : }
1002 0 : if (stmt->else_body != NIL)
1003 : {
1004 0 : dump_ind();
1005 0 : printf(" ELSE\n");
1006 0 : dump_stmts(stmt->else_body);
1007 : }
1008 0 : dump_ind();
1009 0 : printf(" ENDIF\n");
1010 0 : }
1011 :
1012 : static void
1013 0 : dump_case(PLpgSQL_stmt_case *stmt)
1014 : {
1015 : ListCell *l;
1016 :
1017 0 : dump_ind();
1018 0 : printf("CASE %d ", stmt->t_varno);
1019 0 : if (stmt->t_expr)
1020 0 : dump_expr(stmt->t_expr);
1021 0 : printf("\n");
1022 0 : dump_indent += 6;
1023 0 : foreach(l, stmt->case_when_list)
1024 : {
1025 0 : PLpgSQL_case_when *cwt = (PLpgSQL_case_when *) lfirst(l);
1026 :
1027 0 : dump_ind();
1028 0 : printf("WHEN ");
1029 0 : dump_expr(cwt->expr);
1030 0 : printf("\n");
1031 0 : dump_ind();
1032 0 : printf("THEN\n");
1033 0 : dump_indent += 2;
1034 0 : dump_stmts(cwt->stmts);
1035 0 : dump_indent -= 2;
1036 : }
1037 0 : if (stmt->have_else)
1038 : {
1039 0 : dump_ind();
1040 0 : printf("ELSE\n");
1041 0 : dump_indent += 2;
1042 0 : dump_stmts(stmt->else_stmts);
1043 0 : dump_indent -= 2;
1044 : }
1045 0 : dump_indent -= 6;
1046 0 : dump_ind();
1047 0 : printf(" ENDCASE\n");
1048 0 : }
1049 :
1050 : static void
1051 0 : dump_loop(PLpgSQL_stmt_loop *stmt)
1052 : {
1053 0 : dump_ind();
1054 0 : printf("LOOP\n");
1055 :
1056 0 : dump_stmts(stmt->body);
1057 :
1058 0 : dump_ind();
1059 0 : printf(" ENDLOOP\n");
1060 0 : }
1061 :
1062 : static void
1063 0 : dump_while(PLpgSQL_stmt_while *stmt)
1064 : {
1065 0 : dump_ind();
1066 0 : printf("WHILE ");
1067 0 : dump_expr(stmt->cond);
1068 0 : printf("\n");
1069 :
1070 0 : dump_stmts(stmt->body);
1071 :
1072 0 : dump_ind();
1073 0 : printf(" ENDWHILE\n");
1074 0 : }
1075 :
1076 : static void
1077 0 : dump_fori(PLpgSQL_stmt_fori *stmt)
1078 : {
1079 0 : dump_ind();
1080 0 : printf("FORI %s %s\n", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL");
1081 :
1082 0 : dump_indent += 2;
1083 0 : dump_ind();
1084 0 : printf(" lower = ");
1085 0 : dump_expr(stmt->lower);
1086 0 : printf("\n");
1087 0 : dump_ind();
1088 0 : printf(" upper = ");
1089 0 : dump_expr(stmt->upper);
1090 0 : printf("\n");
1091 0 : if (stmt->step)
1092 : {
1093 0 : dump_ind();
1094 0 : printf(" step = ");
1095 0 : dump_expr(stmt->step);
1096 0 : printf("\n");
1097 : }
1098 0 : dump_indent -= 2;
1099 :
1100 0 : dump_stmts(stmt->body);
1101 :
1102 0 : dump_ind();
1103 0 : printf(" ENDFORI\n");
1104 0 : }
1105 :
1106 : static void
1107 0 : dump_fors(PLpgSQL_stmt_fors *stmt)
1108 : {
1109 0 : dump_ind();
1110 0 : printf("FORS %s ", stmt->var->refname);
1111 0 : dump_expr(stmt->query);
1112 0 : printf("\n");
1113 :
1114 0 : dump_stmts(stmt->body);
1115 :
1116 0 : dump_ind();
1117 0 : printf(" ENDFORS\n");
1118 0 : }
1119 :
1120 : static void
1121 0 : dump_forc(PLpgSQL_stmt_forc *stmt)
1122 : {
1123 0 : dump_ind();
1124 0 : printf("FORC %s ", stmt->var->refname);
1125 0 : printf("curvar=%d\n", stmt->curvar);
1126 :
1127 0 : dump_indent += 2;
1128 0 : if (stmt->argquery != NULL)
1129 : {
1130 0 : dump_ind();
1131 0 : printf(" arguments = ");
1132 0 : dump_expr(stmt->argquery);
1133 0 : printf("\n");
1134 : }
1135 0 : dump_indent -= 2;
1136 :
1137 0 : dump_stmts(stmt->body);
1138 :
1139 0 : dump_ind();
1140 0 : printf(" ENDFORC\n");
1141 0 : }
1142 :
1143 : static void
1144 0 : dump_foreach_a(PLpgSQL_stmt_foreach_a *stmt)
1145 : {
1146 0 : dump_ind();
1147 0 : printf("FOREACHA var %d ", stmt->varno);
1148 0 : if (stmt->slice != 0)
1149 0 : printf("SLICE %d ", stmt->slice);
1150 0 : printf("IN ");
1151 0 : dump_expr(stmt->expr);
1152 0 : printf("\n");
1153 :
1154 0 : dump_stmts(stmt->body);
1155 :
1156 0 : dump_ind();
1157 0 : printf(" ENDFOREACHA");
1158 0 : }
1159 :
1160 : static void
1161 0 : dump_open(PLpgSQL_stmt_open *stmt)
1162 : {
1163 0 : dump_ind();
1164 0 : printf("OPEN curvar=%d\n", stmt->curvar);
1165 :
1166 0 : dump_indent += 2;
1167 0 : if (stmt->argquery != NULL)
1168 : {
1169 0 : dump_ind();
1170 0 : printf(" arguments = '");
1171 0 : dump_expr(stmt->argquery);
1172 0 : printf("'\n");
1173 : }
1174 0 : if (stmt->query != NULL)
1175 : {
1176 0 : dump_ind();
1177 0 : printf(" query = '");
1178 0 : dump_expr(stmt->query);
1179 0 : printf("'\n");
1180 : }
1181 0 : if (stmt->dynquery != NULL)
1182 : {
1183 0 : dump_ind();
1184 0 : printf(" execute = '");
1185 0 : dump_expr(stmt->dynquery);
1186 0 : printf("'\n");
1187 :
1188 0 : if (stmt->params != NIL)
1189 : {
1190 : ListCell *lc;
1191 : int i;
1192 :
1193 0 : dump_indent += 2;
1194 0 : dump_ind();
1195 0 : printf(" USING\n");
1196 0 : dump_indent += 2;
1197 0 : i = 1;
1198 0 : foreach(lc, stmt->params)
1199 : {
1200 0 : dump_ind();
1201 0 : printf(" parameter $%d: ", i++);
1202 0 : dump_expr((PLpgSQL_expr *) lfirst(lc));
1203 0 : printf("\n");
1204 : }
1205 0 : dump_indent -= 4;
1206 : }
1207 : }
1208 0 : dump_indent -= 2;
1209 0 : }
1210 :
1211 : static void
1212 0 : dump_fetch(PLpgSQL_stmt_fetch *stmt)
1213 : {
1214 0 : dump_ind();
1215 :
1216 0 : if (!stmt->is_move)
1217 : {
1218 0 : printf("FETCH curvar=%d\n", stmt->curvar);
1219 0 : dump_cursor_direction(stmt);
1220 :
1221 0 : dump_indent += 2;
1222 0 : if (stmt->target != NULL)
1223 : {
1224 0 : dump_ind();
1225 0 : printf(" target = %d %s\n",
1226 : stmt->target->dno, stmt->target->refname);
1227 : }
1228 0 : dump_indent -= 2;
1229 : }
1230 : else
1231 : {
1232 0 : printf("MOVE curvar=%d\n", stmt->curvar);
1233 0 : dump_cursor_direction(stmt);
1234 : }
1235 0 : }
1236 :
1237 : static void
1238 0 : dump_cursor_direction(PLpgSQL_stmt_fetch *stmt)
1239 : {
1240 0 : dump_indent += 2;
1241 0 : dump_ind();
1242 0 : switch (stmt->direction)
1243 : {
1244 0 : case FETCH_FORWARD:
1245 0 : printf(" FORWARD ");
1246 0 : break;
1247 0 : case FETCH_BACKWARD:
1248 0 : printf(" BACKWARD ");
1249 0 : break;
1250 0 : case FETCH_ABSOLUTE:
1251 0 : printf(" ABSOLUTE ");
1252 0 : break;
1253 0 : case FETCH_RELATIVE:
1254 0 : printf(" RELATIVE ");
1255 0 : break;
1256 0 : default:
1257 0 : printf("??? unknown cursor direction %d", stmt->direction);
1258 : }
1259 :
1260 0 : if (stmt->expr)
1261 : {
1262 0 : dump_expr(stmt->expr);
1263 0 : printf("\n");
1264 : }
1265 : else
1266 0 : printf("%ld\n", stmt->how_many);
1267 :
1268 0 : dump_indent -= 2;
1269 0 : }
1270 :
1271 : static void
1272 0 : dump_close(PLpgSQL_stmt_close *stmt)
1273 : {
1274 0 : dump_ind();
1275 0 : printf("CLOSE curvar=%d\n", stmt->curvar);
1276 0 : }
1277 :
1278 : static void
1279 0 : dump_perform(PLpgSQL_stmt_perform *stmt)
1280 : {
1281 0 : dump_ind();
1282 0 : printf("PERFORM expr = ");
1283 0 : dump_expr(stmt->expr);
1284 0 : printf("\n");
1285 0 : }
1286 :
1287 : static void
1288 0 : dump_call(PLpgSQL_stmt_call *stmt)
1289 : {
1290 0 : dump_ind();
1291 0 : printf("%s expr = ", stmt->is_call ? "CALL" : "DO");
1292 0 : dump_expr(stmt->expr);
1293 0 : printf("\n");
1294 0 : }
1295 :
1296 : static void
1297 0 : dump_commit(PLpgSQL_stmt_commit *stmt)
1298 : {
1299 0 : dump_ind();
1300 0 : if (stmt->chain)
1301 0 : printf("COMMIT AND CHAIN\n");
1302 : else
1303 0 : printf("COMMIT\n");
1304 0 : }
1305 :
1306 : static void
1307 0 : dump_rollback(PLpgSQL_stmt_rollback *stmt)
1308 : {
1309 0 : dump_ind();
1310 0 : if (stmt->chain)
1311 0 : printf("ROLLBACK AND CHAIN\n");
1312 : else
1313 0 : printf("ROLLBACK\n");
1314 0 : }
1315 :
1316 : static void
1317 0 : dump_exit(PLpgSQL_stmt_exit *stmt)
1318 : {
1319 0 : dump_ind();
1320 0 : printf("%s", stmt->is_exit ? "EXIT" : "CONTINUE");
1321 0 : if (stmt->label != NULL)
1322 0 : printf(" label='%s'", stmt->label);
1323 0 : if (stmt->cond != NULL)
1324 : {
1325 0 : printf(" WHEN ");
1326 0 : dump_expr(stmt->cond);
1327 : }
1328 0 : printf("\n");
1329 0 : }
1330 :
1331 : static void
1332 0 : dump_return(PLpgSQL_stmt_return *stmt)
1333 : {
1334 0 : dump_ind();
1335 0 : printf("RETURN ");
1336 0 : if (stmt->retvarno >= 0)
1337 0 : printf("variable %d", stmt->retvarno);
1338 0 : else if (stmt->expr != NULL)
1339 0 : dump_expr(stmt->expr);
1340 : else
1341 0 : printf("NULL");
1342 0 : printf("\n");
1343 0 : }
1344 :
1345 : static void
1346 0 : dump_return_next(PLpgSQL_stmt_return_next *stmt)
1347 : {
1348 0 : dump_ind();
1349 0 : printf("RETURN NEXT ");
1350 0 : if (stmt->retvarno >= 0)
1351 0 : printf("variable %d", stmt->retvarno);
1352 0 : else if (stmt->expr != NULL)
1353 0 : dump_expr(stmt->expr);
1354 : else
1355 0 : printf("NULL");
1356 0 : printf("\n");
1357 0 : }
1358 :
1359 : static void
1360 0 : dump_return_query(PLpgSQL_stmt_return_query *stmt)
1361 : {
1362 0 : dump_ind();
1363 0 : if (stmt->query)
1364 : {
1365 0 : printf("RETURN QUERY ");
1366 0 : dump_expr(stmt->query);
1367 0 : printf("\n");
1368 : }
1369 : else
1370 : {
1371 0 : printf("RETURN QUERY EXECUTE ");
1372 0 : dump_expr(stmt->dynquery);
1373 0 : printf("\n");
1374 0 : if (stmt->params != NIL)
1375 : {
1376 : ListCell *lc;
1377 : int i;
1378 :
1379 0 : dump_indent += 2;
1380 0 : dump_ind();
1381 0 : printf(" USING\n");
1382 0 : dump_indent += 2;
1383 0 : i = 1;
1384 0 : foreach(lc, stmt->params)
1385 : {
1386 0 : dump_ind();
1387 0 : printf(" parameter $%d: ", i++);
1388 0 : dump_expr((PLpgSQL_expr *) lfirst(lc));
1389 0 : printf("\n");
1390 : }
1391 0 : dump_indent -= 4;
1392 : }
1393 : }
1394 0 : }
1395 :
1396 : static void
1397 0 : dump_raise(PLpgSQL_stmt_raise *stmt)
1398 : {
1399 : ListCell *lc;
1400 0 : int i = 0;
1401 :
1402 0 : dump_ind();
1403 0 : printf("RAISE level=%d", stmt->elog_level);
1404 0 : if (stmt->condname)
1405 0 : printf(" condname='%s'", stmt->condname);
1406 0 : if (stmt->message)
1407 0 : printf(" message='%s'", stmt->message);
1408 0 : printf("\n");
1409 0 : dump_indent += 2;
1410 0 : foreach(lc, stmt->params)
1411 : {
1412 0 : dump_ind();
1413 0 : printf(" parameter %d: ", i++);
1414 0 : dump_expr((PLpgSQL_expr *) lfirst(lc));
1415 0 : printf("\n");
1416 : }
1417 0 : if (stmt->options)
1418 : {
1419 0 : dump_ind();
1420 0 : printf(" USING\n");
1421 0 : dump_indent += 2;
1422 0 : foreach(lc, stmt->options)
1423 : {
1424 0 : PLpgSQL_raise_option *opt = (PLpgSQL_raise_option *) lfirst(lc);
1425 :
1426 0 : dump_ind();
1427 0 : switch (opt->opt_type)
1428 : {
1429 0 : case PLPGSQL_RAISEOPTION_ERRCODE:
1430 0 : printf(" ERRCODE = ");
1431 0 : break;
1432 0 : case PLPGSQL_RAISEOPTION_MESSAGE:
1433 0 : printf(" MESSAGE = ");
1434 0 : break;
1435 0 : case PLPGSQL_RAISEOPTION_DETAIL:
1436 0 : printf(" DETAIL = ");
1437 0 : break;
1438 0 : case PLPGSQL_RAISEOPTION_HINT:
1439 0 : printf(" HINT = ");
1440 0 : break;
1441 0 : case PLPGSQL_RAISEOPTION_COLUMN:
1442 0 : printf(" COLUMN = ");
1443 0 : break;
1444 0 : case PLPGSQL_RAISEOPTION_CONSTRAINT:
1445 0 : printf(" CONSTRAINT = ");
1446 0 : break;
1447 0 : case PLPGSQL_RAISEOPTION_DATATYPE:
1448 0 : printf(" DATATYPE = ");
1449 0 : break;
1450 0 : case PLPGSQL_RAISEOPTION_TABLE:
1451 0 : printf(" TABLE = ");
1452 0 : break;
1453 0 : case PLPGSQL_RAISEOPTION_SCHEMA:
1454 0 : printf(" SCHEMA = ");
1455 0 : break;
1456 : }
1457 0 : dump_expr(opt->expr);
1458 0 : printf("\n");
1459 : }
1460 0 : dump_indent -= 2;
1461 : }
1462 0 : dump_indent -= 2;
1463 0 : }
1464 :
1465 : static void
1466 0 : dump_assert(PLpgSQL_stmt_assert *stmt)
1467 : {
1468 0 : dump_ind();
1469 0 : printf("ASSERT ");
1470 0 : dump_expr(stmt->cond);
1471 0 : printf("\n");
1472 :
1473 0 : dump_indent += 2;
1474 0 : if (stmt->message != NULL)
1475 : {
1476 0 : dump_ind();
1477 0 : printf(" MESSAGE = ");
1478 0 : dump_expr(stmt->message);
1479 0 : printf("\n");
1480 : }
1481 0 : dump_indent -= 2;
1482 0 : }
1483 :
1484 : static void
1485 0 : dump_execsql(PLpgSQL_stmt_execsql *stmt)
1486 : {
1487 0 : dump_ind();
1488 0 : printf("EXECSQL ");
1489 0 : dump_expr(stmt->sqlstmt);
1490 0 : printf("\n");
1491 :
1492 0 : dump_indent += 2;
1493 0 : if (stmt->target != NULL)
1494 : {
1495 0 : dump_ind();
1496 0 : printf(" INTO%s target = %d %s\n",
1497 : stmt->strict ? " STRICT" : "",
1498 : stmt->target->dno, stmt->target->refname);
1499 : }
1500 0 : dump_indent -= 2;
1501 0 : }
1502 :
1503 : static void
1504 0 : dump_dynexecute(PLpgSQL_stmt_dynexecute *stmt)
1505 : {
1506 0 : dump_ind();
1507 0 : printf("EXECUTE ");
1508 0 : dump_expr(stmt->query);
1509 0 : printf("\n");
1510 :
1511 0 : dump_indent += 2;
1512 0 : if (stmt->target != NULL)
1513 : {
1514 0 : dump_ind();
1515 0 : printf(" INTO%s target = %d %s\n",
1516 : stmt->strict ? " STRICT" : "",
1517 : stmt->target->dno, stmt->target->refname);
1518 : }
1519 0 : if (stmt->params != NIL)
1520 : {
1521 : ListCell *lc;
1522 : int i;
1523 :
1524 0 : dump_ind();
1525 0 : printf(" USING\n");
1526 0 : dump_indent += 2;
1527 0 : i = 1;
1528 0 : foreach(lc, stmt->params)
1529 : {
1530 0 : dump_ind();
1531 0 : printf(" parameter %d: ", i++);
1532 0 : dump_expr((PLpgSQL_expr *) lfirst(lc));
1533 0 : printf("\n");
1534 : }
1535 0 : dump_indent -= 2;
1536 : }
1537 0 : dump_indent -= 2;
1538 0 : }
1539 :
1540 : static void
1541 0 : dump_dynfors(PLpgSQL_stmt_dynfors *stmt)
1542 : {
1543 0 : dump_ind();
1544 0 : printf("FORS %s EXECUTE ", stmt->var->refname);
1545 0 : dump_expr(stmt->query);
1546 0 : printf("\n");
1547 0 : if (stmt->params != NIL)
1548 : {
1549 : ListCell *lc;
1550 : int i;
1551 :
1552 0 : dump_indent += 2;
1553 0 : dump_ind();
1554 0 : printf(" USING\n");
1555 0 : dump_indent += 2;
1556 0 : i = 1;
1557 0 : foreach(lc, stmt->params)
1558 : {
1559 0 : dump_ind();
1560 0 : printf(" parameter $%d: ", i++);
1561 0 : dump_expr((PLpgSQL_expr *) lfirst(lc));
1562 0 : printf("\n");
1563 : }
1564 0 : dump_indent -= 4;
1565 : }
1566 0 : dump_stmts(stmt->body);
1567 0 : dump_ind();
1568 0 : printf(" ENDFORS\n");
1569 0 : }
1570 :
1571 : static void
1572 0 : dump_getdiag(PLpgSQL_stmt_getdiag *stmt)
1573 : {
1574 : ListCell *lc;
1575 :
1576 0 : dump_ind();
1577 0 : printf("GET %s DIAGNOSTICS ", stmt->is_stacked ? "STACKED" : "CURRENT");
1578 0 : foreach(lc, stmt->diag_items)
1579 : {
1580 0 : PLpgSQL_diag_item *diag_item = (PLpgSQL_diag_item *) lfirst(lc);
1581 :
1582 0 : if (lc != list_head(stmt->diag_items))
1583 0 : printf(", ");
1584 :
1585 0 : printf("{var %d} = %s", diag_item->target,
1586 : plpgsql_getdiag_kindname(diag_item->kind));
1587 : }
1588 0 : printf("\n");
1589 0 : }
1590 :
1591 : static void
1592 0 : dump_expr(PLpgSQL_expr *expr)
1593 : {
1594 0 : printf("'%s'", expr->query);
1595 0 : if (expr->target_param >= 0)
1596 0 : printf(" target %d%s", expr->target_param,
1597 : expr->target_is_local ? " (local)" : "");
1598 0 : }
1599 :
1600 : void
1601 0 : plpgsql_dumptree(PLpgSQL_function *func)
1602 : {
1603 : int i;
1604 : PLpgSQL_datum *d;
1605 :
1606 0 : printf("\nExecution tree of successfully compiled PL/pgSQL function %s:\n",
1607 : func->fn_signature);
1608 :
1609 0 : printf("\nFunction's data area:\n");
1610 0 : for (i = 0; i < func->ndatums; i++)
1611 : {
1612 0 : d = func->datums[i];
1613 :
1614 0 : printf(" entry %d: ", i);
1615 0 : switch (d->dtype)
1616 : {
1617 0 : case PLPGSQL_DTYPE_VAR:
1618 : case PLPGSQL_DTYPE_PROMISE:
1619 : {
1620 0 : PLpgSQL_var *var = (PLpgSQL_var *) d;
1621 :
1622 0 : printf("VAR %-16s type %s (typoid %u) atttypmod %d\n",
1623 : var->refname, var->datatype->typname,
1624 : var->datatype->typoid,
1625 : var->datatype->atttypmod);
1626 0 : if (var->isconst)
1627 0 : printf(" CONSTANT\n");
1628 0 : if (var->notnull)
1629 0 : printf(" NOT NULL\n");
1630 0 : if (var->default_val != NULL)
1631 : {
1632 0 : printf(" DEFAULT ");
1633 0 : dump_expr(var->default_val);
1634 0 : printf("\n");
1635 : }
1636 0 : if (var->cursor_explicit_expr != NULL)
1637 : {
1638 0 : if (var->cursor_explicit_argrow >= 0)
1639 0 : printf(" CURSOR argument row %d\n", var->cursor_explicit_argrow);
1640 :
1641 0 : printf(" CURSOR IS ");
1642 0 : dump_expr(var->cursor_explicit_expr);
1643 0 : printf("\n");
1644 : }
1645 0 : if (var->promise != PLPGSQL_PROMISE_NONE)
1646 0 : printf(" PROMISE %d\n",
1647 : (int) var->promise);
1648 : }
1649 0 : break;
1650 0 : case PLPGSQL_DTYPE_ROW:
1651 : {
1652 0 : PLpgSQL_row *row = (PLpgSQL_row *) d;
1653 :
1654 0 : printf("ROW %-16s fields", row->refname);
1655 0 : for (int j = 0; j < row->nfields; j++)
1656 : {
1657 0 : printf(" %s=var %d", row->fieldnames[j],
1658 : row->varnos[j]);
1659 : }
1660 0 : printf("\n");
1661 : }
1662 0 : break;
1663 0 : case PLPGSQL_DTYPE_REC:
1664 0 : printf("REC %-16s typoid %u\n",
1665 : ((PLpgSQL_rec *) d)->refname,
1666 : ((PLpgSQL_rec *) d)->rectypeid);
1667 0 : if (((PLpgSQL_rec *) d)->isconst)
1668 0 : printf(" CONSTANT\n");
1669 0 : if (((PLpgSQL_rec *) d)->notnull)
1670 0 : printf(" NOT NULL\n");
1671 0 : if (((PLpgSQL_rec *) d)->default_val != NULL)
1672 : {
1673 0 : printf(" DEFAULT ");
1674 0 : dump_expr(((PLpgSQL_rec *) d)->default_val);
1675 0 : printf("\n");
1676 : }
1677 0 : break;
1678 0 : case PLPGSQL_DTYPE_RECFIELD:
1679 0 : printf("RECFIELD %-16s of REC %d\n",
1680 : ((PLpgSQL_recfield *) d)->fieldname,
1681 : ((PLpgSQL_recfield *) d)->recparentno);
1682 0 : break;
1683 0 : default:
1684 0 : printf("??? unknown data type %d\n", d->dtype);
1685 : }
1686 : }
1687 0 : printf("\nFunction's statements:\n");
1688 :
1689 0 : dump_indent = 0;
1690 0 : printf("%3d:", func->action->lineno);
1691 0 : dump_block(func->action);
1692 0 : printf("\nEnd of execution tree of function %s\n\n", func->fn_signature);
1693 0 : fflush(stdout);
1694 0 : }
|