LCOV - code coverage report
Current view: top level - src/pl/plpgsql/src - pl_funcs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 31.5 % 937 295
Test Date: 2026-10-09 10:15:47 Functions: 33.3 % 51 17
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 43.1 % 524 226

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

Generated by: LCOV version 2.0-1