LCOV - code coverage report
Current view: top level - src/pl/plpgsql/src - pl_funcs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 295 937 31.5 %
Date: 2026-02-07 15:18:00 Functions: 17 51 33.3 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.16