LCOV - code coverage report
Current view: top level - src/pl/plpgsql/src - pl_funcs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 31.5 % 937 295
Test Date: 2026-05-10 04:16:29 Functions: 33.3 % 51 17
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         6068 : plpgsql_ns_init(void)
      44              : {
      45         6068 :     ns_top = NULL;
      46         6068 : }
      47              : 
      48              : 
      49              : /* ----------
      50              :  * plpgsql_ns_push          Create a new namespace level
      51              :  * ----------
      52              :  */
      53              : void
      54        13427 : plpgsql_ns_push(const char *label, PLpgSQL_label_type label_type)
      55              : {
      56        13427 :     if (label == NULL)
      57         7228 :         label = "";
      58        13427 :     plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, (int) label_type, label);
      59        13427 : }
      60              : 
      61              : 
      62              : /* ----------
      63              :  * plpgsql_ns_pop           Pop entries back to (and including) the last label
      64              :  * ----------
      65              :  */
      66              : void
      67         7242 : plpgsql_ns_pop(void)
      68              : {
      69              :     Assert(ns_top != NULL);
      70        12037 :     while (ns_top->itemtype != PLPGSQL_NSTYPE_LABEL)
      71         4795 :         ns_top = ns_top->prev;
      72         7242 :     ns_top = ns_top->prev;
      73         7242 : }
      74              : 
      75              : 
      76              : /* ----------
      77              :  * plpgsql_ns_top           Fetch the current namespace chain end
      78              :  * ----------
      79              :  */
      80              : PLpgSQL_nsitem *
      81        61285 : plpgsql_ns_top(void)
      82              : {
      83        61285 :     return ns_top;
      84              : }
      85              : 
      86              : 
      87              : /* ----------
      88              :  * plpgsql_ns_additem       Add an item to the current namespace chain
      89              :  * ----------
      90              :  */
      91              : void
      92        60060 : 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        60060 :     nse = palloc(offsetof(PLpgSQL_nsitem, name) + strlen(name) + 1);
     101        60060 :     nse->itemtype = itemtype;
     102        60060 :     nse->itemno = itemno;
     103        60060 :     nse->prev = ns_top;
     104        60060 :     strcpy(nse->name, name);
     105        60060 :     ns_top = nse;
     106        60060 : }
     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        59089 : 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       116735 :     while (ns_cur != NULL)
     136              :     {
     137              :         PLpgSQL_nsitem *nsitem;
     138              : 
     139              :         /* Check this level for unqualified match to variable name */
     140       104769 :         for (nsitem = ns_cur;
     141       397269 :              nsitem->itemtype != PLPGSQL_NSTYPE_LABEL;
     142       292500 :              nsitem = nsitem->prev)
     143              :         {
     144       330563 :             if (strcmp(nsitem->name, name1) == 0)
     145              :             {
     146        38063 :                 if (name2 == NULL ||
     147         8755 :                     nsitem->itemtype != PLPGSQL_NSTYPE_VAR)
     148              :                 {
     149        38063 :                     if (names_used)
     150        27411 :                         *names_used = 1;
     151        38063 :                     return nsitem;
     152              :                 }
     153              :             }
     154              :         }
     155              : 
     156              :         /* Check this level for qualified match to variable name */
     157        66706 :         if (name2 != NULL &&
     158         9802 :             strcmp(nsitem->name, name1) == 0)
     159              :         {
     160           82 :             for (nsitem = ns_cur;
     161          142 :                  nsitem->itemtype != PLPGSQL_NSTYPE_LABEL;
     162           60 :                  nsitem = nsitem->prev)
     163              :             {
     164          141 :                 if (strcmp(nsitem->name, name2) == 0)
     165              :                 {
     166           81 :                     if (name3 == NULL ||
     167           36 :                         nsitem->itemtype != PLPGSQL_NSTYPE_VAR)
     168              :                     {
     169           81 :                         if (names_used)
     170           81 :                             *names_used = 2;
     171           81 :                         return nsitem;
     172              :                     }
     173              :                 }
     174              :             }
     175              :         }
     176              : 
     177        66625 :         if (localmode)
     178         8979 :             break;              /* do not look into upper levels */
     179              : 
     180        57646 :         ns_cur = nsitem->prev;
     181              :     }
     182              : 
     183              :     /* This is just to suppress possibly-uninitialized-variable warnings */
     184        20945 :     if (names_used)
     185         3302 :         *names_used = 0;
     186        20945 :     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           16 : plpgsql_ns_lookup_label(PLpgSQL_nsitem *ns_cur, const char *name)
     196              : {
     197           43 :     while (ns_cur != NULL)
     198              :     {
     199           41 :         if (ns_cur->itemtype == PLPGSQL_NSTYPE_LABEL &&
     200           34 :             strcmp(ns_cur->name, name) == 0)
     201           14 :             return ns_cur;
     202           27 :         ns_cur = ns_cur->prev;
     203              :     }
     204              : 
     205            2 :     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          116 : plpgsql_ns_find_nearest_loop(PLpgSQL_nsitem *ns_cur)
     215              : {
     216          143 :     while (ns_cur != NULL)
     217              :     {
     218          141 :         if (ns_cur->itemtype == PLPGSQL_NSTYPE_LABEL &&
     219          124 :             ns_cur->itemno == PLPGSQL_LABEL_LOOP)
     220          114 :             return ns_cur;
     221           27 :         ns_cur = ns_cur->prev;
     222              :     }
     223              : 
     224            2 :     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        15746 : plpgsql_stmt_typename(PLpgSQL_stmt *stmt)
     233              : {
     234        15746 :     switch (stmt->cmd_type)
     235              :     {
     236            0 :         case PLPGSQL_STMT_BLOCK:
     237            0 :             return _("statement block");
     238          360 :         case PLPGSQL_STMT_ASSIGN:
     239          360 :             return _("assignment");
     240            0 :         case PLPGSQL_STMT_IF:
     241            0 :             return "IF";
     242            3 :         case PLPGSQL_STMT_CASE:
     243            3 :             return "CASE";
     244            0 :         case PLPGSQL_STMT_LOOP:
     245            0 :             return "LOOP";
     246            0 :         case PLPGSQL_STMT_WHILE:
     247            0 :             return "WHILE";
     248            3 :         case PLPGSQL_STMT_FORI:
     249            3 :             return _("FOR with integer loop variable");
     250           10 :         case PLPGSQL_STMT_FORS:
     251           10 :             return _("FOR over SELECT rows");
     252            0 :         case PLPGSQL_STMT_FORC:
     253            0 :             return _("FOR over cursor");
     254           12 :         case PLPGSQL_STMT_FOREACH_A:
     255           12 :             return _("FOREACH over array");
     256            0 :         case PLPGSQL_STMT_EXIT:
     257            0 :             return ((PLpgSQL_stmt_exit *) stmt)->is_exit ? "EXIT" : "CONTINUE";
     258           86 :         case PLPGSQL_STMT_RETURN:
     259           86 :             return "RETURN";
     260            2 :         case PLPGSQL_STMT_RETURN_NEXT:
     261            2 :             return "RETURN NEXT";
     262            9 :         case PLPGSQL_STMT_RETURN_QUERY:
     263            9 :             return "RETURN QUERY";
     264        11487 :         case PLPGSQL_STMT_RAISE:
     265        11487 :             return "RAISE";
     266           16 :         case PLPGSQL_STMT_ASSERT:
     267           16 :             return "ASSERT";
     268         2361 :         case PLPGSQL_STMT_EXECSQL:
     269         2361 :             return _("SQL statement");
     270          268 :         case PLPGSQL_STMT_DYNEXECUTE:
     271          268 :             return "EXECUTE";
     272           42 :         case PLPGSQL_STMT_DYNFORS:
     273           42 :             return _("FOR over EXECUTE statement");
     274           36 :         case PLPGSQL_STMT_GETDIAG:
     275           36 :             return ((PLpgSQL_stmt_getdiag *) stmt)->is_stacked ?
     276           36 :                 "GET STACKED DIAGNOSTICS" : "GET DIAGNOSTICS";
     277            8 :         case PLPGSQL_STMT_OPEN:
     278            8 :             return "OPEN";
     279            4 :         case PLPGSQL_STMT_FETCH:
     280            4 :             return ((PLpgSQL_stmt_fetch *) stmt)->is_move ? "MOVE" : "FETCH";
     281            0 :         case PLPGSQL_STMT_CLOSE:
     282            0 :             return "CLOSE";
     283          986 :         case PLPGSQL_STMT_PERFORM:
     284          986 :             return "PERFORM";
     285           39 :         case PLPGSQL_STMT_CALL:
     286           39 :             return ((PLpgSQL_stmt_call *) stmt)->is_call ? "CALL" : "DO";
     287           11 :         case PLPGSQL_STMT_COMMIT:
     288           11 :             return "COMMIT";
     289            3 :         case PLPGSQL_STMT_ROLLBACK:
     290            3 :             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         8274 : 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         8274 :     switch (stmt->cmd_type)
     375              :     {
     376         1885 :         case PLPGSQL_STMT_BLOCK:
     377              :             {
     378         1885 :                 PLpgSQL_stmt_block *bstmt = (PLpgSQL_stmt_block *) stmt;
     379              : 
     380         8500 :                 S_LIST_WALK(bstmt->body);
     381         1885 :                 if (bstmt->exceptions)
     382              :                 {
     383         1072 :                     foreach_ptr(PLpgSQL_exception, exc, bstmt->exceptions->exc_list)
     384              :                     {
     385              :                         /* conditions list has no interesting sub-structure */
     386         1079 :                         S_LIST_WALK(exc->action);
     387              :                     }
     388              :                 }
     389         1885 :                 break;
     390              :             }
     391          608 :         case PLPGSQL_STMT_ASSIGN:
     392              :             {
     393          608 :                 PLpgSQL_stmt_assign *astmt = (PLpgSQL_stmt_assign *) stmt;
     394              : 
     395          608 :                 E_WALK(astmt->expr);
     396          608 :                 break;
     397              :             }
     398          230 :         case PLPGSQL_STMT_IF:
     399              :             {
     400          230 :                 PLpgSQL_stmt_if *ifstmt = (PLpgSQL_stmt_if *) stmt;
     401              : 
     402          230 :                 E_WALK(ifstmt->cond);
     403          828 :                 S_LIST_WALK(ifstmt->then_body);
     404          460 :                 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          551 :                 S_LIST_WALK(ifstmt->else_body);
     410          230 :                 break;
     411              :             }
     412            1 :         case PLPGSQL_STMT_CASE:
     413              :             {
     414            1 :                 PLpgSQL_stmt_case *cstmt = (PLpgSQL_stmt_case *) stmt;
     415              : 
     416            1 :                 E_WALK(cstmt->t_expr);
     417            7 :                 foreach_ptr(PLpgSQL_case_when, cwt, cstmt->case_when_list)
     418              :                 {
     419            5 :                     E_WALK(cwt->expr);
     420           15 :                     S_LIST_WALK(cwt->stmts);
     421              :                 }
     422            2 :                 S_LIST_WALK(cstmt->else_stmts);
     423            1 :                 break;
     424              :             }
     425           27 :         case PLPGSQL_STMT_LOOP:
     426              :             {
     427           27 :                 PLpgSQL_stmt_loop *lstmt = (PLpgSQL_stmt_loop *) stmt;
     428              : 
     429          125 :                 S_LIST_WALK(lstmt->body);
     430           27 :                 break;
     431              :             }
     432           35 :         case PLPGSQL_STMT_WHILE:
     433              :             {
     434           35 :                 PLpgSQL_stmt_while *wstmt = (PLpgSQL_stmt_while *) stmt;
     435              : 
     436           35 :                 E_WALK(wstmt->cond);
     437          147 :                 S_LIST_WALK(wstmt->body);
     438           35 :                 break;
     439              :             }
     440          305 :         case PLPGSQL_STMT_FORI:
     441              :             {
     442          305 :                 PLpgSQL_stmt_fori *fori = (PLpgSQL_stmt_fori *) stmt;
     443              : 
     444          305 :                 E_WALK(fori->lower);
     445          305 :                 E_WALK(fori->upper);
     446          305 :                 E_WALK(fori->step);
     447         1177 :                 S_LIST_WALK(fori->body);
     448          305 :                 break;
     449              :             }
     450           91 :         case PLPGSQL_STMT_FORS:
     451              :             {
     452           91 :                 PLpgSQL_stmt_fors *fors = (PLpgSQL_stmt_fors *) stmt;
     453              : 
     454          523 :                 S_LIST_WALK(fors->body);
     455           91 :                 E_WALK(fors->query);
     456           91 :                 break;
     457              :             }
     458           33 :         case PLPGSQL_STMT_FORC:
     459              :             {
     460           33 :                 PLpgSQL_stmt_forc *forc = (PLpgSQL_stmt_forc *) stmt;
     461              : 
     462          104 :                 S_LIST_WALK(forc->body);
     463           33 :                 E_WALK(forc->argquery);
     464           33 :                 break;
     465              :             }
     466           32 :         case PLPGSQL_STMT_FOREACH_A:
     467              :             {
     468           32 :                 PLpgSQL_stmt_foreach_a *fstmt = (PLpgSQL_stmt_foreach_a *) stmt;
     469              : 
     470           32 :                 E_WALK(fstmt->expr);
     471           96 :                 S_LIST_WALK(fstmt->body);
     472           32 :                 break;
     473              :             }
     474           46 :         case PLPGSQL_STMT_EXIT:
     475              :             {
     476           46 :                 PLpgSQL_stmt_exit *estmt = (PLpgSQL_stmt_exit *) stmt;
     477              : 
     478           46 :                 E_WALK(estmt->cond);
     479           46 :                 break;
     480              :             }
     481         1656 :         case PLPGSQL_STMT_RETURN:
     482              :             {
     483         1656 :                 PLpgSQL_stmt_return *rstmt = (PLpgSQL_stmt_return *) stmt;
     484              : 
     485         1656 :                 E_WALK(rstmt->expr);
     486         1656 :                 break;
     487              :             }
     488           39 :         case PLPGSQL_STMT_RETURN_NEXT:
     489              :             {
     490           39 :                 PLpgSQL_stmt_return_next *rstmt = (PLpgSQL_stmt_return_next *) stmt;
     491              : 
     492           39 :                 E_WALK(rstmt->expr);
     493           39 :                 break;
     494              :             }
     495           25 :         case PLPGSQL_STMT_RETURN_QUERY:
     496              :             {
     497           25 :                 PLpgSQL_stmt_return_query *rstmt = (PLpgSQL_stmt_return_query *) stmt;
     498              : 
     499           25 :                 E_WALK(rstmt->query);
     500           25 :                 E_WALK(rstmt->dynquery);
     501           50 :                 E_LIST_WALK(rstmt->params);
     502           25 :                 break;
     503              :             }
     504         1112 :         case PLPGSQL_STMT_RAISE:
     505              :             {
     506         1112 :                 PLpgSQL_stmt_raise *rstmt = (PLpgSQL_stmt_raise *) stmt;
     507              : 
     508         3552 :                 E_LIST_WALK(rstmt->params);
     509         2389 :                 foreach_ptr(PLpgSQL_raise_option, opt, rstmt->options)
     510              :                 {
     511          165 :                     E_WALK(opt->expr);
     512              :                 }
     513         1112 :                 break;
     514              :             }
     515           28 :         case PLPGSQL_STMT_ASSERT:
     516              :             {
     517           28 :                 PLpgSQL_stmt_assert *astmt = (PLpgSQL_stmt_assert *) stmt;
     518              : 
     519           28 :                 E_WALK(astmt->cond);
     520           28 :                 E_WALK(astmt->message);
     521           28 :                 break;
     522              :             }
     523         1051 :         case PLPGSQL_STMT_EXECSQL:
     524              :             {
     525         1051 :                 PLpgSQL_stmt_execsql *xstmt = (PLpgSQL_stmt_execsql *) stmt;
     526              : 
     527         1051 :                 E_WALK(xstmt->sqlstmt);
     528         1051 :                 break;
     529              :             }
     530          278 :         case PLPGSQL_STMT_DYNEXECUTE:
     531              :             {
     532          278 :                 PLpgSQL_stmt_dynexecute *dstmt = (PLpgSQL_stmt_dynexecute *) stmt;
     533              : 
     534          278 :                 E_WALK(dstmt->query);
     535          568 :                 E_LIST_WALK(dstmt->params);
     536          278 :                 break;
     537              :             }
     538           52 :         case PLPGSQL_STMT_DYNFORS:
     539              :             {
     540           52 :                 PLpgSQL_stmt_dynfors *dstmt = (PLpgSQL_stmt_dynfors *) stmt;
     541              : 
     542          156 :                 S_LIST_WALK(dstmt->body);
     543           52 :                 E_WALK(dstmt->query);
     544          104 :                 E_LIST_WALK(dstmt->params);
     545           52 :                 break;
     546              :             }
     547           72 :         case PLPGSQL_STMT_GETDIAG:
     548              :             {
     549              :                 /* no interesting sub-structure */
     550           72 :                 break;
     551              :             }
     552           29 :         case PLPGSQL_STMT_OPEN:
     553              :             {
     554           29 :                 PLpgSQL_stmt_open *ostmt = (PLpgSQL_stmt_open *) stmt;
     555              : 
     556           29 :                 E_WALK(ostmt->argquery);
     557           29 :                 E_WALK(ostmt->query);
     558           29 :                 E_WALK(ostmt->dynquery);
     559           58 :                 E_LIST_WALK(ostmt->params);
     560           29 :                 break;
     561              :             }
     562           53 :         case PLPGSQL_STMT_FETCH:
     563              :             {
     564           53 :                 PLpgSQL_stmt_fetch *fstmt = (PLpgSQL_stmt_fetch *) stmt;
     565              : 
     566           53 :                 E_WALK(fstmt->expr);
     567           53 :                 break;
     568              :             }
     569           24 :         case PLPGSQL_STMT_CLOSE:
     570              :             {
     571              :                 /* no interesting sub-structure */
     572           24 :                 break;
     573              :             }
     574          471 :         case PLPGSQL_STMT_PERFORM:
     575              :             {
     576          471 :                 PLpgSQL_stmt_perform *pstmt = (PLpgSQL_stmt_perform *) stmt;
     577              : 
     578          471 :                 E_WALK(pstmt->expr);
     579          471 :                 break;
     580              :             }
     581           44 :         case PLPGSQL_STMT_CALL:
     582              :             {
     583           44 :                 PLpgSQL_stmt_call *cstmt = (PLpgSQL_stmt_call *) stmt;
     584              : 
     585           44 :                 E_WALK(cstmt->expr);
     586           44 :                 break;
     587              :             }
     588           47 :         case PLPGSQL_STMT_COMMIT:
     589              :         case PLPGSQL_STMT_ROLLBACK:
     590              :             {
     591              :                 /* no interesting sub-structure */
     592           47 :                 break;
     593              :             }
     594            0 :         default:
     595            0 :             elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
     596              :             break;
     597              :     }
     598         8274 : }
     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         1531 : mark_stmt(PLpgSQL_stmt *stmt, Bitmapset *local_dnos)
     624              : {
     625         1531 :     if (stmt == NULL)
     626            0 :         return;
     627         1531 :     if (stmt->cmd_type == PLPGSQL_STMT_BLOCK)
     628              :     {
     629          500 :         PLpgSQL_stmt_block *block = (PLpgSQL_stmt_block *) stmt;
     630              : 
     631          500 :         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          274 :             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          226 :             local_dnos = bms_copy(local_dnos);
     650          291 :             for (int i = 0; i < block->n_initvars; i++)
     651           65 :                 local_dnos = bms_add_member(local_dnos, block->initvarnos[i]);
     652          226 :             plpgsql_statement_tree_walker(stmt, mark_stmt, mark_expr,
     653              :                                           local_dnos);
     654          226 :             bms_free(local_dnos);
     655              :         }
     656              :     }
     657              :     else
     658         1031 :         plpgsql_statement_tree_walker(stmt, mark_stmt, mark_expr, local_dnos);
     659              : }
     660              : 
     661              : static void
     662         1083 : 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         1083 :     if (expr && expr->target_param >= 0)
     669           76 :         expr->target_is_local = bms_is_member(expr->target_param, local_dnos);
     670         1083 : }
     671              : 
     672              : void
     673          262 : 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          262 :     local_dnos = NULL;
     679          348 :     for (int i = 0; i < func->fn_nargs; i++)
     680           86 :         local_dnos = bms_add_member(local_dnos, func->fn_argvarnos[i]);
     681          262 :     mark_stmt((PLpgSQL_stmt *) func->action, local_dnos);
     682          262 :     bms_free(local_dnos);
     683          262 : }
     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         6743 : free_stmt(PLpgSQL_stmt *stmt, void *context)
     699              : {
     700         6743 :     if (stmt == NULL)
     701            0 :         return;
     702         6743 :     plpgsql_statement_tree_walker(stmt, free_stmt, free_expr, NULL);
     703              : }
     704              : 
     705              : static void
     706        13826 : free_expr(PLpgSQL_expr *expr, void *context)
     707              : {
     708        13826 :     if (expr && expr->plan)
     709              :     {
     710         4148 :         SPI_freeplan(expr->plan);
     711         4148 :         expr->plan = NULL;
     712              :     }
     713        13826 : }
     714              : 
     715              : void
     716         1285 : 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         6103 :     for (i = 0; i < func->ndatums; i++)
     725              :     {
     726         4818 :         PLpgSQL_datum *d = func->datums[i];
     727              : 
     728         4818 :         switch (d->dtype)
     729              :         {
     730         3538 :             case PLPGSQL_DTYPE_VAR:
     731              :             case PLPGSQL_DTYPE_PROMISE:
     732              :                 {
     733         3538 :                     PLpgSQL_var *var = (PLpgSQL_var *) d;
     734              : 
     735         3538 :                     free_expr(var->default_val, NULL);
     736         3538 :                     free_expr(var->cursor_explicit_expr, NULL);
     737              :                 }
     738         3538 :                 break;
     739          227 :             case PLPGSQL_DTYPE_ROW:
     740          227 :                 break;
     741          495 :             case PLPGSQL_DTYPE_REC:
     742              :                 {
     743          495 :                     PLpgSQL_rec *rec = (PLpgSQL_rec *) d;
     744              : 
     745          495 :                     free_expr(rec->default_val, NULL);
     746              :                 }
     747          495 :                 break;
     748          558 :             case PLPGSQL_DTYPE_RECFIELD:
     749          558 :                 break;
     750            0 :             default:
     751            0 :                 elog(ERROR, "unrecognized data type: %d", d->dtype);
     752              :         }
     753              :     }
     754         1285 :     func->ndatums = 0;
     755              : 
     756              :     /* Release plans in statement tree */
     757         1285 :     free_stmt((PLpgSQL_stmt *) func->action, NULL);
     758         1285 :     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         1285 :     if (func->fn_cxt)
     766         1285 :         MemoryContextDelete(func->fn_cxt);
     767         1285 :     func->fn_cxt = NULL;
     768         1285 : }
     769              : 
     770              : /* Deletion callback used by funccache.c */
     771              : void
     772          467 : plpgsql_delete_callback(CachedFunction *cfunc)
     773              : {
     774          467 :     plpgsql_free_function_memory((PLpgSQL_function *) cfunc);
     775          467 : }
     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 2.0-1