Header And Logo

PostgreSQL
| The world's most advanced open source database.

pl_funcs.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * pl_funcs.c       - Misc functions for the PL/pgSQL
00004  *            procedural language
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/pl/plpgsql/src/pl_funcs.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 
00016 #include "plpgsql.h"
00017 
00018 #include "utils/memutils.h"
00019 
00020 
00021 /* ----------
00022  * Local variables for namespace handling
00023  *
00024  * The namespace structure actually forms a tree, of which only one linear
00025  * list or "chain" (from the youngest item to the root) is accessible from
00026  * any one plpgsql statement.  During initial parsing of a function, ns_top
00027  * points to the youngest item accessible from the block currently being
00028  * parsed.  We store the entire tree, however, since at runtime we will need
00029  * to access the chain that's relevant to any one statement.
00030  *
00031  * Block boundaries in the namespace chain are marked by PLPGSQL_NSTYPE_LABEL
00032  * items.
00033  * ----------
00034  */
00035 static PLpgSQL_nsitem *ns_top = NULL;
00036 
00037 
00038 /* ----------
00039  * plpgsql_ns_init          Initialize namespace processing for a new function
00040  * ----------
00041  */
00042 void
00043 plpgsql_ns_init(void)
00044 {
00045     ns_top = NULL;
00046 }
00047 
00048 
00049 /* ----------
00050  * plpgsql_ns_push          Create a new namespace level
00051  * ----------
00052  */
00053 void
00054 plpgsql_ns_push(const char *label)
00055 {
00056     if (label == NULL)
00057         label = "";
00058     plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, 0, label);
00059 }
00060 
00061 
00062 /* ----------
00063  * plpgsql_ns_pop           Pop entries back to (and including) the last label
00064  * ----------
00065  */
00066 void
00067 plpgsql_ns_pop(void)
00068 {
00069     Assert(ns_top != NULL);
00070     while (ns_top->itemtype != PLPGSQL_NSTYPE_LABEL)
00071         ns_top = ns_top->prev;
00072     ns_top = ns_top->prev;
00073 }
00074 
00075 
00076 /* ----------
00077  * plpgsql_ns_top           Fetch the current namespace chain end
00078  * ----------
00079  */
00080 PLpgSQL_nsitem *
00081 plpgsql_ns_top(void)
00082 {
00083     return ns_top;
00084 }
00085 
00086 
00087 /* ----------
00088  * plpgsql_ns_additem       Add an item to the current namespace chain
00089  * ----------
00090  */
00091 void
00092 plpgsql_ns_additem(int itemtype, int itemno, const char *name)
00093 {
00094     PLpgSQL_nsitem *nse;
00095 
00096     Assert(name != NULL);
00097     /* first item added must be a label */
00098     Assert(ns_top != NULL || itemtype == PLPGSQL_NSTYPE_LABEL);
00099 
00100     nse = palloc(sizeof(PLpgSQL_nsitem) + strlen(name));
00101     nse->itemtype = itemtype;
00102     nse->itemno = itemno;
00103     nse->prev = ns_top;
00104     strcpy(nse->name, name);
00105     ns_top = nse;
00106 }
00107 
00108 
00109 /* ----------
00110  * plpgsql_ns_lookup        Lookup an identifier in the given namespace chain
00111  *
00112  * Note that this only searches for variables, not labels.
00113  *
00114  * If localmode is TRUE, only the topmost block level is searched.
00115  *
00116  * name1 must be non-NULL.  Pass NULL for name2 and/or name3 if parsing a name
00117  * with fewer than three components.
00118  *
00119  * If names_used isn't NULL, *names_used receives the number of names
00120  * matched: 0 if no match, 1 if name1 matched an unqualified variable name,
00121  * 2 if name1 and name2 matched a block label + variable name.
00122  *
00123  * Note that name3 is never directly matched to anything.  However, if it
00124  * isn't NULL, we will disregard qualified matches to scalar variables.
00125  * Similarly, if name2 isn't NULL, we disregard unqualified matches to
00126  * scalar variables.
00127  * ----------
00128  */
00129 PLpgSQL_nsitem *
00130 plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur, bool localmode,
00131                   const char *name1, const char *name2, const char *name3,
00132                   int *names_used)
00133 {
00134     /* Outer loop iterates once per block level in the namespace chain */
00135     while (ns_cur != NULL)
00136     {
00137         PLpgSQL_nsitem *nsitem;
00138 
00139         /* Check this level for unqualified match to variable name */
00140         for (nsitem = ns_cur;
00141              nsitem->itemtype != PLPGSQL_NSTYPE_LABEL;
00142              nsitem = nsitem->prev)
00143         {
00144             if (strcmp(nsitem->name, name1) == 0)
00145             {
00146                 if (name2 == NULL ||
00147                     nsitem->itemtype != PLPGSQL_NSTYPE_VAR)
00148                 {
00149                     if (names_used)
00150                         *names_used = 1;
00151                     return nsitem;
00152                 }
00153             }
00154         }
00155 
00156         /* Check this level for qualified match to variable name */
00157         if (name2 != NULL &&
00158             strcmp(nsitem->name, name1) == 0)
00159         {
00160             for (nsitem = ns_cur;
00161                  nsitem->itemtype != PLPGSQL_NSTYPE_LABEL;
00162                  nsitem = nsitem->prev)
00163             {
00164                 if (strcmp(nsitem->name, name2) == 0)
00165                 {
00166                     if (name3 == NULL ||
00167                         nsitem->itemtype != PLPGSQL_NSTYPE_VAR)
00168                     {
00169                         if (names_used)
00170                             *names_used = 2;
00171                         return nsitem;
00172                     }
00173                 }
00174             }
00175         }
00176 
00177         if (localmode)
00178             break;              /* do not look into upper levels */
00179 
00180         ns_cur = nsitem->prev;
00181     }
00182 
00183     /* This is just to suppress possibly-uninitialized-variable warnings */
00184     if (names_used)
00185         *names_used = 0;
00186     return NULL;                /* No match found */
00187 }
00188 
00189 
00190 /* ----------
00191  * plpgsql_ns_lookup_label      Lookup a label in the given namespace chain
00192  * ----------
00193  */
00194 PLpgSQL_nsitem *
00195 plpgsql_ns_lookup_label(PLpgSQL_nsitem *ns_cur, const char *name)
00196 {
00197     while (ns_cur != NULL)
00198     {
00199         if (ns_cur->itemtype == PLPGSQL_NSTYPE_LABEL &&
00200             strcmp(ns_cur->name, name) == 0)
00201             return ns_cur;
00202         ns_cur = ns_cur->prev;
00203     }
00204 
00205     return NULL;                /* label not found */
00206 }
00207 
00208 
00209 /*
00210  * Statement type as a string, for use in error messages etc.
00211  */
00212 const char *
00213 plpgsql_stmt_typename(PLpgSQL_stmt *stmt)
00214 {
00215     switch ((enum PLpgSQL_stmt_types) stmt->cmd_type)
00216     {
00217         case PLPGSQL_STMT_BLOCK:
00218             return _("statement block");
00219         case PLPGSQL_STMT_ASSIGN:
00220             return _("assignment");
00221         case PLPGSQL_STMT_IF:
00222             return "IF";
00223         case PLPGSQL_STMT_CASE:
00224             return "CASE";
00225         case PLPGSQL_STMT_LOOP:
00226             return "LOOP";
00227         case PLPGSQL_STMT_WHILE:
00228             return "WHILE";
00229         case PLPGSQL_STMT_FORI:
00230             return _("FOR with integer loop variable");
00231         case PLPGSQL_STMT_FORS:
00232             return _("FOR over SELECT rows");
00233         case PLPGSQL_STMT_FORC:
00234             return _("FOR over cursor");
00235         case PLPGSQL_STMT_FOREACH_A:
00236             return _("FOREACH over array");
00237         case PLPGSQL_STMT_EXIT:
00238             return "EXIT";
00239         case PLPGSQL_STMT_RETURN:
00240             return "RETURN";
00241         case PLPGSQL_STMT_RETURN_NEXT:
00242             return "RETURN NEXT";
00243         case PLPGSQL_STMT_RETURN_QUERY:
00244             return "RETURN QUERY";
00245         case PLPGSQL_STMT_RAISE:
00246             return "RAISE";
00247         case PLPGSQL_STMT_EXECSQL:
00248             return _("SQL statement");
00249         case PLPGSQL_STMT_DYNEXECUTE:
00250             return _("EXECUTE statement");
00251         case PLPGSQL_STMT_DYNFORS:
00252             return _("FOR over EXECUTE statement");
00253         case PLPGSQL_STMT_GETDIAG:
00254             return "GET DIAGNOSTICS";
00255         case PLPGSQL_STMT_OPEN:
00256             return "OPEN";
00257         case PLPGSQL_STMT_FETCH:
00258             return "FETCH";
00259         case PLPGSQL_STMT_CLOSE:
00260             return "CLOSE";
00261         case PLPGSQL_STMT_PERFORM:
00262             return "PERFORM";
00263     }
00264 
00265     return "unknown";
00266 }
00267 
00268 /*
00269  * GET DIAGNOSTICS item name as a string, for use in error messages etc.
00270  */
00271 const char *
00272 plpgsql_getdiag_kindname(int kind)
00273 {
00274     switch (kind)
00275     {
00276         case PLPGSQL_GETDIAG_ROW_COUNT:
00277             return "ROW_COUNT";
00278         case PLPGSQL_GETDIAG_RESULT_OID:
00279             return "RESULT_OID";
00280         case PLPGSQL_GETDIAG_ERROR_CONTEXT:
00281             return "PG_EXCEPTION_CONTEXT";
00282         case PLPGSQL_GETDIAG_ERROR_DETAIL:
00283             return "PG_EXCEPTION_DETAIL";
00284         case PLPGSQL_GETDIAG_ERROR_HINT:
00285             return "PG_EXCEPTION_HINT";
00286         case PLPGSQL_GETDIAG_RETURNED_SQLSTATE:
00287             return "RETURNED_SQLSTATE";
00288         case PLPGSQL_GETDIAG_MESSAGE_TEXT:
00289             return "MESSAGE_TEXT";
00290     }
00291 
00292     return "unknown";
00293 }
00294 
00295 
00296 /**********************************************************************
00297  * Release memory when a PL/pgSQL function is no longer needed
00298  *
00299  * The code for recursing through the function tree is really only
00300  * needed to locate PLpgSQL_expr nodes, which may contain references
00301  * to saved SPI Plans that must be freed.  The function tree itself,
00302  * along with subsidiary data, is freed in one swoop by freeing the
00303  * function's permanent memory context.
00304  **********************************************************************/
00305 static void free_stmt(PLpgSQL_stmt *stmt);
00306 static void free_block(PLpgSQL_stmt_block *block);
00307 static void free_assign(PLpgSQL_stmt_assign *stmt);
00308 static void free_if(PLpgSQL_stmt_if *stmt);
00309 static void free_case(PLpgSQL_stmt_case *stmt);
00310 static void free_loop(PLpgSQL_stmt_loop *stmt);
00311 static void free_while(PLpgSQL_stmt_while *stmt);
00312 static void free_fori(PLpgSQL_stmt_fori *stmt);
00313 static void free_fors(PLpgSQL_stmt_fors *stmt);
00314 static void free_forc(PLpgSQL_stmt_forc *stmt);
00315 static void free_foreach_a(PLpgSQL_stmt_foreach_a *stmt);
00316 static void free_exit(PLpgSQL_stmt_exit *stmt);
00317 static void free_return(PLpgSQL_stmt_return *stmt);
00318 static void free_return_next(PLpgSQL_stmt_return_next *stmt);
00319 static void free_return_query(PLpgSQL_stmt_return_query *stmt);
00320 static void free_raise(PLpgSQL_stmt_raise *stmt);
00321 static void free_execsql(PLpgSQL_stmt_execsql *stmt);
00322 static void free_dynexecute(PLpgSQL_stmt_dynexecute *stmt);
00323 static void free_dynfors(PLpgSQL_stmt_dynfors *stmt);
00324 static void free_getdiag(PLpgSQL_stmt_getdiag *stmt);
00325 static void free_open(PLpgSQL_stmt_open *stmt);
00326 static void free_fetch(PLpgSQL_stmt_fetch *stmt);
00327 static void free_close(PLpgSQL_stmt_close *stmt);
00328 static void free_perform(PLpgSQL_stmt_perform *stmt);
00329 static void free_expr(PLpgSQL_expr *expr);
00330 
00331 
00332 static void
00333 free_stmt(PLpgSQL_stmt *stmt)
00334 {
00335     switch ((enum PLpgSQL_stmt_types) stmt->cmd_type)
00336     {
00337         case PLPGSQL_STMT_BLOCK:
00338             free_block((PLpgSQL_stmt_block *) stmt);
00339             break;
00340         case PLPGSQL_STMT_ASSIGN:
00341             free_assign((PLpgSQL_stmt_assign *) stmt);
00342             break;
00343         case PLPGSQL_STMT_IF:
00344             free_if((PLpgSQL_stmt_if *) stmt);
00345             break;
00346         case PLPGSQL_STMT_CASE:
00347             free_case((PLpgSQL_stmt_case *) stmt);
00348             break;
00349         case PLPGSQL_STMT_LOOP:
00350             free_loop((PLpgSQL_stmt_loop *) stmt);
00351             break;
00352         case PLPGSQL_STMT_WHILE:
00353             free_while((PLpgSQL_stmt_while *) stmt);
00354             break;
00355         case PLPGSQL_STMT_FORI:
00356             free_fori((PLpgSQL_stmt_fori *) stmt);
00357             break;
00358         case PLPGSQL_STMT_FORS:
00359             free_fors((PLpgSQL_stmt_fors *) stmt);
00360             break;
00361         case PLPGSQL_STMT_FORC:
00362             free_forc((PLpgSQL_stmt_forc *) stmt);
00363             break;
00364         case PLPGSQL_STMT_FOREACH_A:
00365             free_foreach_a((PLpgSQL_stmt_foreach_a *) stmt);
00366             break;
00367         case PLPGSQL_STMT_EXIT:
00368             free_exit((PLpgSQL_stmt_exit *) stmt);
00369             break;
00370         case PLPGSQL_STMT_RETURN:
00371             free_return((PLpgSQL_stmt_return *) stmt);
00372             break;
00373         case PLPGSQL_STMT_RETURN_NEXT:
00374             free_return_next((PLpgSQL_stmt_return_next *) stmt);
00375             break;
00376         case PLPGSQL_STMT_RETURN_QUERY:
00377             free_return_query((PLpgSQL_stmt_return_query *) stmt);
00378             break;
00379         case PLPGSQL_STMT_RAISE:
00380             free_raise((PLpgSQL_stmt_raise *) stmt);
00381             break;
00382         case PLPGSQL_STMT_EXECSQL:
00383             free_execsql((PLpgSQL_stmt_execsql *) stmt);
00384             break;
00385         case PLPGSQL_STMT_DYNEXECUTE:
00386             free_dynexecute((PLpgSQL_stmt_dynexecute *) stmt);
00387             break;
00388         case PLPGSQL_STMT_DYNFORS:
00389             free_dynfors((PLpgSQL_stmt_dynfors *) stmt);
00390             break;
00391         case PLPGSQL_STMT_GETDIAG:
00392             free_getdiag((PLpgSQL_stmt_getdiag *) stmt);
00393             break;
00394         case PLPGSQL_STMT_OPEN:
00395             free_open((PLpgSQL_stmt_open *) stmt);
00396             break;
00397         case PLPGSQL_STMT_FETCH:
00398             free_fetch((PLpgSQL_stmt_fetch *) stmt);
00399             break;
00400         case PLPGSQL_STMT_CLOSE:
00401             free_close((PLpgSQL_stmt_close *) stmt);
00402             break;
00403         case PLPGSQL_STMT_PERFORM:
00404             free_perform((PLpgSQL_stmt_perform *) stmt);
00405             break;
00406         default:
00407             elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
00408             break;
00409     }
00410 }
00411 
00412 static void
00413 free_stmts(List *stmts)
00414 {
00415     ListCell   *s;
00416 
00417     foreach(s, stmts)
00418     {
00419         free_stmt((PLpgSQL_stmt *) lfirst(s));
00420     }
00421 }
00422 
00423 static void
00424 free_block(PLpgSQL_stmt_block *block)
00425 {
00426     free_stmts(block->body);
00427     if (block->exceptions)
00428     {
00429         ListCell   *e;
00430 
00431         foreach(e, block->exceptions->exc_list)
00432         {
00433             PLpgSQL_exception *exc = (PLpgSQL_exception *) lfirst(e);
00434 
00435             free_stmts(exc->action);
00436         }
00437     }
00438 }
00439 
00440 static void
00441 free_assign(PLpgSQL_stmt_assign *stmt)
00442 {
00443     free_expr(stmt->expr);
00444 }
00445 
00446 static void
00447 free_if(PLpgSQL_stmt_if *stmt)
00448 {
00449     ListCell   *l;
00450 
00451     free_expr(stmt->cond);
00452     free_stmts(stmt->then_body);
00453     foreach(l, stmt->elsif_list)
00454     {
00455         PLpgSQL_if_elsif *elif = (PLpgSQL_if_elsif *) lfirst(l);
00456 
00457         free_expr(elif->cond);
00458         free_stmts(elif->stmts);
00459     }
00460     free_stmts(stmt->else_body);
00461 }
00462 
00463 static void
00464 free_case(PLpgSQL_stmt_case *stmt)
00465 {
00466     ListCell   *l;
00467 
00468     free_expr(stmt->t_expr);
00469     foreach(l, stmt->case_when_list)
00470     {
00471         PLpgSQL_case_when *cwt = (PLpgSQL_case_when *) lfirst(l);
00472 
00473         free_expr(cwt->expr);
00474         free_stmts(cwt->stmts);
00475     }
00476     free_stmts(stmt->else_stmts);
00477 }
00478 
00479 static void
00480 free_loop(PLpgSQL_stmt_loop *stmt)
00481 {
00482     free_stmts(stmt->body);
00483 }
00484 
00485 static void
00486 free_while(PLpgSQL_stmt_while *stmt)
00487 {
00488     free_expr(stmt->cond);
00489     free_stmts(stmt->body);
00490 }
00491 
00492 static void
00493 free_fori(PLpgSQL_stmt_fori *stmt)
00494 {
00495     free_expr(stmt->lower);
00496     free_expr(stmt->upper);
00497     free_expr(stmt->step);
00498     free_stmts(stmt->body);
00499 }
00500 
00501 static void
00502 free_fors(PLpgSQL_stmt_fors *stmt)
00503 {
00504     free_stmts(stmt->body);
00505     free_expr(stmt->query);
00506 }
00507 
00508 static void
00509 free_forc(PLpgSQL_stmt_forc *stmt)
00510 {
00511     free_stmts(stmt->body);
00512     free_expr(stmt->argquery);
00513 }
00514 
00515 static void
00516 free_foreach_a(PLpgSQL_stmt_foreach_a *stmt)
00517 {
00518     free_expr(stmt->expr);
00519     free_stmts(stmt->body);
00520 }
00521 
00522 static void
00523 free_open(PLpgSQL_stmt_open *stmt)
00524 {
00525     ListCell   *lc;
00526 
00527     free_expr(stmt->argquery);
00528     free_expr(stmt->query);
00529     free_expr(stmt->dynquery);
00530     foreach(lc, stmt->params)
00531     {
00532         free_expr((PLpgSQL_expr *) lfirst(lc));
00533     }
00534 }
00535 
00536 static void
00537 free_fetch(PLpgSQL_stmt_fetch *stmt)
00538 {
00539     free_expr(stmt->expr);
00540 }
00541 
00542 static void
00543 free_close(PLpgSQL_stmt_close *stmt)
00544 {
00545 }
00546 
00547 static void
00548 free_perform(PLpgSQL_stmt_perform *stmt)
00549 {
00550     free_expr(stmt->expr);
00551 }
00552 
00553 static void
00554 free_exit(PLpgSQL_stmt_exit *stmt)
00555 {
00556     free_expr(stmt->cond);
00557 }
00558 
00559 static void
00560 free_return(PLpgSQL_stmt_return *stmt)
00561 {
00562     free_expr(stmt->expr);
00563 }
00564 
00565 static void
00566 free_return_next(PLpgSQL_stmt_return_next *stmt)
00567 {
00568     free_expr(stmt->expr);
00569 }
00570 
00571 static void
00572 free_return_query(PLpgSQL_stmt_return_query *stmt)
00573 {
00574     ListCell   *lc;
00575 
00576     free_expr(stmt->query);
00577     free_expr(stmt->dynquery);
00578     foreach(lc, stmt->params)
00579     {
00580         free_expr((PLpgSQL_expr *) lfirst(lc));
00581     }
00582 }
00583 
00584 static void
00585 free_raise(PLpgSQL_stmt_raise *stmt)
00586 {
00587     ListCell   *lc;
00588 
00589     foreach(lc, stmt->params)
00590     {
00591         free_expr((PLpgSQL_expr *) lfirst(lc));
00592     }
00593     foreach(lc, stmt->options)
00594     {
00595         PLpgSQL_raise_option *opt = (PLpgSQL_raise_option *) lfirst(lc);
00596 
00597         free_expr(opt->expr);
00598     }
00599 }
00600 
00601 static void
00602 free_execsql(PLpgSQL_stmt_execsql *stmt)
00603 {
00604     free_expr(stmt->sqlstmt);
00605 }
00606 
00607 static void
00608 free_dynexecute(PLpgSQL_stmt_dynexecute *stmt)
00609 {
00610     ListCell   *lc;
00611 
00612     free_expr(stmt->query);
00613     foreach(lc, stmt->params)
00614     {
00615         free_expr((PLpgSQL_expr *) lfirst(lc));
00616     }
00617 }
00618 
00619 static void
00620 free_dynfors(PLpgSQL_stmt_dynfors *stmt)
00621 {
00622     ListCell   *lc;
00623 
00624     free_stmts(stmt->body);
00625     free_expr(stmt->query);
00626     foreach(lc, stmt->params)
00627     {
00628         free_expr((PLpgSQL_expr *) lfirst(lc));
00629     }
00630 }
00631 
00632 static void
00633 free_getdiag(PLpgSQL_stmt_getdiag *stmt)
00634 {
00635 }
00636 
00637 static void
00638 free_expr(PLpgSQL_expr *expr)
00639 {
00640     if (expr && expr->plan)
00641     {
00642         SPI_freeplan(expr->plan);
00643         expr->plan = NULL;
00644     }
00645 }
00646 
00647 void
00648 plpgsql_free_function_memory(PLpgSQL_function *func)
00649 {
00650     int         i;
00651 
00652     /* Better not call this on an in-use function */
00653     Assert(func->use_count == 0);
00654 
00655     /* Release plans associated with variable declarations */
00656     for (i = 0; i < func->ndatums; i++)
00657     {
00658         PLpgSQL_datum *d = func->datums[i];
00659 
00660         switch (d->dtype)
00661         {
00662             case PLPGSQL_DTYPE_VAR:
00663                 {
00664                     PLpgSQL_var *var = (PLpgSQL_var *) d;
00665 
00666                     free_expr(var->default_val);
00667                     free_expr(var->cursor_explicit_expr);
00668                 }
00669                 break;
00670             case PLPGSQL_DTYPE_ROW:
00671                 break;
00672             case PLPGSQL_DTYPE_REC:
00673                 break;
00674             case PLPGSQL_DTYPE_RECFIELD:
00675                 break;
00676             case PLPGSQL_DTYPE_ARRAYELEM:
00677                 free_expr(((PLpgSQL_arrayelem *) d)->subscript);
00678                 break;
00679             default:
00680                 elog(ERROR, "unrecognized data type: %d", d->dtype);
00681         }
00682     }
00683     func->ndatums = 0;
00684 
00685     /* Release plans in statement tree */
00686     if (func->action)
00687         free_block(func->action);
00688     func->action = NULL;
00689 
00690     /*
00691      * And finally, release all memory except the PLpgSQL_function struct
00692      * itself (which has to be kept around because there may be multiple
00693      * fn_extra pointers to it).
00694      */
00695     if (func->fn_cxt)
00696         MemoryContextDelete(func->fn_cxt);
00697     func->fn_cxt = NULL;
00698 }
00699 
00700 
00701 /**********************************************************************
00702  * Debug functions for analyzing the compiled code
00703  **********************************************************************/
00704 static int  dump_indent;
00705 
00706 static void dump_ind(void);
00707 static void dump_stmt(PLpgSQL_stmt *stmt);
00708 static void dump_block(PLpgSQL_stmt_block *block);
00709 static void dump_assign(PLpgSQL_stmt_assign *stmt);
00710 static void dump_if(PLpgSQL_stmt_if *stmt);
00711 static void dump_case(PLpgSQL_stmt_case *stmt);
00712 static void dump_loop(PLpgSQL_stmt_loop *stmt);
00713 static void dump_while(PLpgSQL_stmt_while *stmt);
00714 static void dump_fori(PLpgSQL_stmt_fori *stmt);
00715 static void dump_fors(PLpgSQL_stmt_fors *stmt);
00716 static void dump_forc(PLpgSQL_stmt_forc *stmt);
00717 static void dump_foreach_a(PLpgSQL_stmt_foreach_a *stmt);
00718 static void dump_exit(PLpgSQL_stmt_exit *stmt);
00719 static void dump_return(PLpgSQL_stmt_return *stmt);
00720 static void dump_return_next(PLpgSQL_stmt_return_next *stmt);
00721 static void dump_return_query(PLpgSQL_stmt_return_query *stmt);
00722 static void dump_raise(PLpgSQL_stmt_raise *stmt);
00723 static void dump_execsql(PLpgSQL_stmt_execsql *stmt);
00724 static void dump_dynexecute(PLpgSQL_stmt_dynexecute *stmt);
00725 static void dump_dynfors(PLpgSQL_stmt_dynfors *stmt);
00726 static void dump_getdiag(PLpgSQL_stmt_getdiag *stmt);
00727 static void dump_open(PLpgSQL_stmt_open *stmt);
00728 static void dump_fetch(PLpgSQL_stmt_fetch *stmt);
00729 static void dump_cursor_direction(PLpgSQL_stmt_fetch *stmt);
00730 static void dump_close(PLpgSQL_stmt_close *stmt);
00731 static void dump_perform(PLpgSQL_stmt_perform *stmt);
00732 static void dump_expr(PLpgSQL_expr *expr);
00733 
00734 
00735 static void
00736 dump_ind(void)
00737 {
00738     int         i;
00739 
00740     for (i = 0; i < dump_indent; i++)
00741         printf(" ");
00742 }
00743 
00744 static void
00745 dump_stmt(PLpgSQL_stmt *stmt)
00746 {
00747     printf("%3d:", stmt->lineno);
00748     switch ((enum PLpgSQL_stmt_types) stmt->cmd_type)
00749     {
00750         case PLPGSQL_STMT_BLOCK:
00751             dump_block((PLpgSQL_stmt_block *) stmt);
00752             break;
00753         case PLPGSQL_STMT_ASSIGN:
00754             dump_assign((PLpgSQL_stmt_assign *) stmt);
00755             break;
00756         case PLPGSQL_STMT_IF:
00757             dump_if((PLpgSQL_stmt_if *) stmt);
00758             break;
00759         case PLPGSQL_STMT_CASE:
00760             dump_case((PLpgSQL_stmt_case *) stmt);
00761             break;
00762         case PLPGSQL_STMT_LOOP:
00763             dump_loop((PLpgSQL_stmt_loop *) stmt);
00764             break;
00765         case PLPGSQL_STMT_WHILE:
00766             dump_while((PLpgSQL_stmt_while *) stmt);
00767             break;
00768         case PLPGSQL_STMT_FORI:
00769             dump_fori((PLpgSQL_stmt_fori *) stmt);
00770             break;
00771         case PLPGSQL_STMT_FORS:
00772             dump_fors((PLpgSQL_stmt_fors *) stmt);
00773             break;
00774         case PLPGSQL_STMT_FORC:
00775             dump_forc((PLpgSQL_stmt_forc *) stmt);
00776             break;
00777         case PLPGSQL_STMT_FOREACH_A:
00778             dump_foreach_a((PLpgSQL_stmt_foreach_a *) stmt);
00779             break;
00780         case PLPGSQL_STMT_EXIT:
00781             dump_exit((PLpgSQL_stmt_exit *) stmt);
00782             break;
00783         case PLPGSQL_STMT_RETURN:
00784             dump_return((PLpgSQL_stmt_return *) stmt);
00785             break;
00786         case PLPGSQL_STMT_RETURN_NEXT:
00787             dump_return_next((PLpgSQL_stmt_return_next *) stmt);
00788             break;
00789         case PLPGSQL_STMT_RETURN_QUERY:
00790             dump_return_query((PLpgSQL_stmt_return_query *) stmt);
00791             break;
00792         case PLPGSQL_STMT_RAISE:
00793             dump_raise((PLpgSQL_stmt_raise *) stmt);
00794             break;
00795         case PLPGSQL_STMT_EXECSQL:
00796             dump_execsql((PLpgSQL_stmt_execsql *) stmt);
00797             break;
00798         case PLPGSQL_STMT_DYNEXECUTE:
00799             dump_dynexecute((PLpgSQL_stmt_dynexecute *) stmt);
00800             break;
00801         case PLPGSQL_STMT_DYNFORS:
00802             dump_dynfors((PLpgSQL_stmt_dynfors *) stmt);
00803             break;
00804         case PLPGSQL_STMT_GETDIAG:
00805             dump_getdiag((PLpgSQL_stmt_getdiag *) stmt);
00806             break;
00807         case PLPGSQL_STMT_OPEN:
00808             dump_open((PLpgSQL_stmt_open *) stmt);
00809             break;
00810         case PLPGSQL_STMT_FETCH:
00811             dump_fetch((PLpgSQL_stmt_fetch *) stmt);
00812             break;
00813         case PLPGSQL_STMT_CLOSE:
00814             dump_close((PLpgSQL_stmt_close *) stmt);
00815             break;
00816         case PLPGSQL_STMT_PERFORM:
00817             dump_perform((PLpgSQL_stmt_perform *) stmt);
00818             break;
00819         default:
00820             elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
00821             break;
00822     }
00823 }
00824 
00825 static void
00826 dump_stmts(List *stmts)
00827 {
00828     ListCell   *s;
00829 
00830     dump_indent += 2;
00831     foreach(s, stmts)
00832         dump_stmt((PLpgSQL_stmt *) lfirst(s));
00833     dump_indent -= 2;
00834 }
00835 
00836 static void
00837 dump_block(PLpgSQL_stmt_block *block)
00838 {
00839     char       *name;
00840 
00841     if (block->label == NULL)
00842         name = "*unnamed*";
00843     else
00844         name = block->label;
00845 
00846     dump_ind();
00847     printf("BLOCK <<%s>>\n", name);
00848 
00849     dump_stmts(block->body);
00850 
00851     if (block->exceptions)
00852     {
00853         ListCell   *e;
00854 
00855         foreach(e, block->exceptions->exc_list)
00856         {
00857             PLpgSQL_exception *exc = (PLpgSQL_exception *) lfirst(e);
00858             PLpgSQL_condition *cond;
00859 
00860             dump_ind();
00861             printf("    EXCEPTION WHEN ");
00862             for (cond = exc->conditions; cond; cond = cond->next)
00863             {
00864                 if (cond != exc->conditions)
00865                     printf(" OR ");
00866                 printf("%s", cond->condname);
00867             }
00868             printf(" THEN\n");
00869             dump_stmts(exc->action);
00870         }
00871     }
00872 
00873     dump_ind();
00874     printf("    END -- %s\n", name);
00875 }
00876 
00877 static void
00878 dump_assign(PLpgSQL_stmt_assign *stmt)
00879 {
00880     dump_ind();
00881     printf("ASSIGN var %d := ", stmt->varno);
00882     dump_expr(stmt->expr);
00883     printf("\n");
00884 }
00885 
00886 static void
00887 dump_if(PLpgSQL_stmt_if *stmt)
00888 {
00889     ListCell   *l;
00890 
00891     dump_ind();
00892     printf("IF ");
00893     dump_expr(stmt->cond);
00894     printf(" THEN\n");
00895     dump_stmts(stmt->then_body);
00896     foreach(l, stmt->elsif_list)
00897     {
00898         PLpgSQL_if_elsif *elif = (PLpgSQL_if_elsif *) lfirst(l);
00899 
00900         dump_ind();
00901         printf("    ELSIF ");
00902         dump_expr(elif->cond);
00903         printf(" THEN\n");
00904         dump_stmts(elif->stmts);
00905     }
00906     if (stmt->else_body != NIL)
00907     {
00908         dump_ind();
00909         printf("    ELSE\n");
00910         dump_stmts(stmt->else_body);
00911     }
00912     dump_ind();
00913     printf("    ENDIF\n");
00914 }
00915 
00916 static void
00917 dump_case(PLpgSQL_stmt_case *stmt)
00918 {
00919     ListCell   *l;
00920 
00921     dump_ind();
00922     printf("CASE %d ", stmt->t_varno);
00923     if (stmt->t_expr)
00924         dump_expr(stmt->t_expr);
00925     printf("\n");
00926     dump_indent += 6;
00927     foreach(l, stmt->case_when_list)
00928     {
00929         PLpgSQL_case_when *cwt = (PLpgSQL_case_when *) lfirst(l);
00930 
00931         dump_ind();
00932         printf("WHEN ");
00933         dump_expr(cwt->expr);
00934         printf("\n");
00935         dump_ind();
00936         printf("THEN\n");
00937         dump_indent += 2;
00938         dump_stmts(cwt->stmts);
00939         dump_indent -= 2;
00940     }
00941     if (stmt->have_else)
00942     {
00943         dump_ind();
00944         printf("ELSE\n");
00945         dump_indent += 2;
00946         dump_stmts(stmt->else_stmts);
00947         dump_indent -= 2;
00948     }
00949     dump_indent -= 6;
00950     dump_ind();
00951     printf("    ENDCASE\n");
00952 }
00953 
00954 static void
00955 dump_loop(PLpgSQL_stmt_loop *stmt)
00956 {
00957     dump_ind();
00958     printf("LOOP\n");
00959 
00960     dump_stmts(stmt->body);
00961 
00962     dump_ind();
00963     printf("    ENDLOOP\n");
00964 }
00965 
00966 static void
00967 dump_while(PLpgSQL_stmt_while *stmt)
00968 {
00969     dump_ind();
00970     printf("WHILE ");
00971     dump_expr(stmt->cond);
00972     printf("\n");
00973 
00974     dump_stmts(stmt->body);
00975 
00976     dump_ind();
00977     printf("    ENDWHILE\n");
00978 }
00979 
00980 static void
00981 dump_fori(PLpgSQL_stmt_fori *stmt)
00982 {
00983     dump_ind();
00984     printf("FORI %s %s\n", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL");
00985 
00986     dump_indent += 2;
00987     dump_ind();
00988     printf("    lower = ");
00989     dump_expr(stmt->lower);
00990     printf("\n");
00991     dump_ind();
00992     printf("    upper = ");
00993     dump_expr(stmt->upper);
00994     printf("\n");
00995     if (stmt->step)
00996     {
00997         dump_ind();
00998         printf("    step = ");
00999         dump_expr(stmt->step);
01000         printf("\n");
01001     }
01002     dump_indent -= 2;
01003 
01004     dump_stmts(stmt->body);
01005 
01006     dump_ind();
01007     printf("    ENDFORI\n");
01008 }
01009 
01010 static void
01011 dump_fors(PLpgSQL_stmt_fors *stmt)
01012 {
01013     dump_ind();
01014     printf("FORS %s ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
01015     dump_expr(stmt->query);
01016     printf("\n");
01017 
01018     dump_stmts(stmt->body);
01019 
01020     dump_ind();
01021     printf("    ENDFORS\n");
01022 }
01023 
01024 static void
01025 dump_forc(PLpgSQL_stmt_forc *stmt)
01026 {
01027     dump_ind();
01028     printf("FORC %s ", stmt->rec->refname);
01029     printf("curvar=%d\n", stmt->curvar);
01030 
01031     dump_indent += 2;
01032     if (stmt->argquery != NULL)
01033     {
01034         dump_ind();
01035         printf("  arguments = ");
01036         dump_expr(stmt->argquery);
01037         printf("\n");
01038     }
01039     dump_indent -= 2;
01040 
01041     dump_stmts(stmt->body);
01042 
01043     dump_ind();
01044     printf("    ENDFORC\n");
01045 }
01046 
01047 static void
01048 dump_foreach_a(PLpgSQL_stmt_foreach_a *stmt)
01049 {
01050     dump_ind();
01051     printf("FOREACHA var %d ", stmt->varno);
01052     if (stmt->slice != 0)
01053         printf("SLICE %d ", stmt->slice);
01054     printf("IN ");
01055     dump_expr(stmt->expr);
01056     printf("\n");
01057 
01058     dump_stmts(stmt->body);
01059 
01060     dump_ind();
01061     printf("    ENDFOREACHA");
01062 }
01063 
01064 static void
01065 dump_open(PLpgSQL_stmt_open *stmt)
01066 {
01067     dump_ind();
01068     printf("OPEN curvar=%d\n", stmt->curvar);
01069 
01070     dump_indent += 2;
01071     if (stmt->argquery != NULL)
01072     {
01073         dump_ind();
01074         printf("  arguments = '");
01075         dump_expr(stmt->argquery);
01076         printf("'\n");
01077     }
01078     if (stmt->query != NULL)
01079     {
01080         dump_ind();
01081         printf("  query = '");
01082         dump_expr(stmt->query);
01083         printf("'\n");
01084     }
01085     if (stmt->dynquery != NULL)
01086     {
01087         dump_ind();
01088         printf("  execute = '");
01089         dump_expr(stmt->dynquery);
01090         printf("'\n");
01091 
01092         if (stmt->params != NIL)
01093         {
01094             ListCell   *lc;
01095             int         i;
01096 
01097             dump_indent += 2;
01098             dump_ind();
01099             printf("    USING\n");
01100             dump_indent += 2;
01101             i = 1;
01102             foreach(lc, stmt->params)
01103             {
01104                 dump_ind();
01105                 printf("    parameter $%d: ", i++);
01106                 dump_expr((PLpgSQL_expr *) lfirst(lc));
01107                 printf("\n");
01108             }
01109             dump_indent -= 4;
01110         }
01111     }
01112     dump_indent -= 2;
01113 }
01114 
01115 static void
01116 dump_fetch(PLpgSQL_stmt_fetch *stmt)
01117 {
01118     dump_ind();
01119 
01120     if (!stmt->is_move)
01121     {
01122         printf("FETCH curvar=%d\n", stmt->curvar);
01123         dump_cursor_direction(stmt);
01124 
01125         dump_indent += 2;
01126         if (stmt->rec != NULL)
01127         {
01128             dump_ind();
01129             printf("    target = %d %s\n", stmt->rec->dno, stmt->rec->refname);
01130         }
01131         if (stmt->row != NULL)
01132         {
01133             dump_ind();
01134             printf("    target = %d %s\n", stmt->row->dno, stmt->row->refname);
01135         }
01136         dump_indent -= 2;
01137     }
01138     else
01139     {
01140         printf("MOVE curvar=%d\n", stmt->curvar);
01141         dump_cursor_direction(stmt);
01142     }
01143 }
01144 
01145 static void
01146 dump_cursor_direction(PLpgSQL_stmt_fetch *stmt)
01147 {
01148     dump_indent += 2;
01149     dump_ind();
01150     switch (stmt->direction)
01151     {
01152         case FETCH_FORWARD:
01153             printf("    FORWARD ");
01154             break;
01155         case FETCH_BACKWARD:
01156             printf("    BACKWARD ");
01157             break;
01158         case FETCH_ABSOLUTE:
01159             printf("    ABSOLUTE ");
01160             break;
01161         case FETCH_RELATIVE:
01162             printf("    RELATIVE ");
01163             break;
01164         default:
01165             printf("??? unknown cursor direction %d", stmt->direction);
01166     }
01167 
01168     if (stmt->expr)
01169     {
01170         dump_expr(stmt->expr);
01171         printf("\n");
01172     }
01173     else
01174         printf("%ld\n", stmt->how_many);
01175 
01176     dump_indent -= 2;
01177 }
01178 
01179 static void
01180 dump_close(PLpgSQL_stmt_close *stmt)
01181 {
01182     dump_ind();
01183     printf("CLOSE curvar=%d\n", stmt->curvar);
01184 }
01185 
01186 static void
01187 dump_perform(PLpgSQL_stmt_perform *stmt)
01188 {
01189     dump_ind();
01190     printf("PERFORM expr = ");
01191     dump_expr(stmt->expr);
01192     printf("\n");
01193 }
01194 
01195 static void
01196 dump_exit(PLpgSQL_stmt_exit *stmt)
01197 {
01198     dump_ind();
01199     printf("%s", stmt->is_exit ? "EXIT" : "CONTINUE");
01200     if (stmt->label != NULL)
01201         printf(" label='%s'", stmt->label);
01202     if (stmt->cond != NULL)
01203     {
01204         printf(" WHEN ");
01205         dump_expr(stmt->cond);
01206     }
01207     printf("\n");
01208 }
01209 
01210 static void
01211 dump_return(PLpgSQL_stmt_return *stmt)
01212 {
01213     dump_ind();
01214     printf("RETURN ");
01215     if (stmt->retvarno >= 0)
01216         printf("variable %d", stmt->retvarno);
01217     else if (stmt->expr != NULL)
01218         dump_expr(stmt->expr);
01219     else
01220         printf("NULL");
01221     printf("\n");
01222 }
01223 
01224 static void
01225 dump_return_next(PLpgSQL_stmt_return_next *stmt)
01226 {
01227     dump_ind();
01228     printf("RETURN NEXT ");
01229     if (stmt->retvarno >= 0)
01230         printf("variable %d", stmt->retvarno);
01231     else if (stmt->expr != NULL)
01232         dump_expr(stmt->expr);
01233     else
01234         printf("NULL");
01235     printf("\n");
01236 }
01237 
01238 static void
01239 dump_return_query(PLpgSQL_stmt_return_query *stmt)
01240 {
01241     dump_ind();
01242     if (stmt->query)
01243     {
01244         printf("RETURN QUERY ");
01245         dump_expr(stmt->query);
01246         printf("\n");
01247     }
01248     else
01249     {
01250         printf("RETURN QUERY EXECUTE ");
01251         dump_expr(stmt->dynquery);
01252         printf("\n");
01253         if (stmt->params != NIL)
01254         {
01255             ListCell   *lc;
01256             int         i;
01257 
01258             dump_indent += 2;
01259             dump_ind();
01260             printf("    USING\n");
01261             dump_indent += 2;
01262             i = 1;
01263             foreach(lc, stmt->params)
01264             {
01265                 dump_ind();
01266                 printf("    parameter $%d: ", i++);
01267                 dump_expr((PLpgSQL_expr *) lfirst(lc));
01268                 printf("\n");
01269             }
01270             dump_indent -= 4;
01271         }
01272     }
01273 }
01274 
01275 static void
01276 dump_raise(PLpgSQL_stmt_raise *stmt)
01277 {
01278     ListCell   *lc;
01279     int         i = 0;
01280 
01281     dump_ind();
01282     printf("RAISE level=%d", stmt->elog_level);
01283     if (stmt->condname)
01284         printf(" condname='%s'", stmt->condname);
01285     if (stmt->message)
01286         printf(" message='%s'", stmt->message);
01287     printf("\n");
01288     dump_indent += 2;
01289     foreach(lc, stmt->params)
01290     {
01291         dump_ind();
01292         printf("    parameter %d: ", i++);
01293         dump_expr((PLpgSQL_expr *) lfirst(lc));
01294         printf("\n");
01295     }
01296     if (stmt->options)
01297     {
01298         dump_ind();
01299         printf("    USING\n");
01300         dump_indent += 2;
01301         foreach(lc, stmt->options)
01302         {
01303             PLpgSQL_raise_option *opt = (PLpgSQL_raise_option *) lfirst(lc);
01304 
01305             dump_ind();
01306             switch (opt->opt_type)
01307             {
01308                 case PLPGSQL_RAISEOPTION_ERRCODE:
01309                     printf("    ERRCODE = ");
01310                     break;
01311                 case PLPGSQL_RAISEOPTION_MESSAGE:
01312                     printf("    MESSAGE = ");
01313                     break;
01314                 case PLPGSQL_RAISEOPTION_DETAIL:
01315                     printf("    DETAIL = ");
01316                     break;
01317                 case PLPGSQL_RAISEOPTION_HINT:
01318                     printf("    HINT = ");
01319                     break;
01320             }
01321             dump_expr(opt->expr);
01322             printf("\n");
01323         }
01324         dump_indent -= 2;
01325     }
01326     dump_indent -= 2;
01327 }
01328 
01329 static void
01330 dump_execsql(PLpgSQL_stmt_execsql *stmt)
01331 {
01332     dump_ind();
01333     printf("EXECSQL ");
01334     dump_expr(stmt->sqlstmt);
01335     printf("\n");
01336 
01337     dump_indent += 2;
01338     if (stmt->rec != NULL)
01339     {
01340         dump_ind();
01341         printf("    INTO%s target = %d %s\n",
01342                stmt->strict ? " STRICT" : "",
01343                stmt->rec->dno, stmt->rec->refname);
01344     }
01345     if (stmt->row != NULL)
01346     {
01347         dump_ind();
01348         printf("    INTO%s target = %d %s\n",
01349                stmt->strict ? " STRICT" : "",
01350                stmt->row->dno, stmt->row->refname);
01351     }
01352     dump_indent -= 2;
01353 }
01354 
01355 static void
01356 dump_dynexecute(PLpgSQL_stmt_dynexecute *stmt)
01357 {
01358     dump_ind();
01359     printf("EXECUTE ");
01360     dump_expr(stmt->query);
01361     printf("\n");
01362 
01363     dump_indent += 2;
01364     if (stmt->rec != NULL)
01365     {
01366         dump_ind();
01367         printf("    INTO%s target = %d %s\n",
01368                stmt->strict ? " STRICT" : "",
01369                stmt->rec->dno, stmt->rec->refname);
01370     }
01371     if (stmt->row != NULL)
01372     {
01373         dump_ind();
01374         printf("    INTO%s target = %d %s\n",
01375                stmt->strict ? " STRICT" : "",
01376                stmt->row->dno, stmt->row->refname);
01377     }
01378     if (stmt->params != NIL)
01379     {
01380         ListCell   *lc;
01381         int         i;
01382 
01383         dump_ind();
01384         printf("    USING\n");
01385         dump_indent += 2;
01386         i = 1;
01387         foreach(lc, stmt->params)
01388         {
01389             dump_ind();
01390             printf("    parameter %d: ", i++);
01391             dump_expr((PLpgSQL_expr *) lfirst(lc));
01392             printf("\n");
01393         }
01394         dump_indent -= 2;
01395     }
01396     dump_indent -= 2;
01397 }
01398 
01399 static void
01400 dump_dynfors(PLpgSQL_stmt_dynfors *stmt)
01401 {
01402     dump_ind();
01403     printf("FORS %s EXECUTE ",
01404            (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
01405     dump_expr(stmt->query);
01406     printf("\n");
01407     if (stmt->params != NIL)
01408     {
01409         ListCell   *lc;
01410         int         i;
01411 
01412         dump_indent += 2;
01413         dump_ind();
01414         printf("    USING\n");
01415         dump_indent += 2;
01416         i = 1;
01417         foreach(lc, stmt->params)
01418         {
01419             dump_ind();
01420             printf("    parameter $%d: ", i++);
01421             dump_expr((PLpgSQL_expr *) lfirst(lc));
01422             printf("\n");
01423         }
01424         dump_indent -= 4;
01425     }
01426     dump_stmts(stmt->body);
01427     dump_ind();
01428     printf("    ENDFORS\n");
01429 }
01430 
01431 static void
01432 dump_getdiag(PLpgSQL_stmt_getdiag *stmt)
01433 {
01434     ListCell   *lc;
01435 
01436     dump_ind();
01437     printf("GET %s DIAGNOSTICS ", stmt->is_stacked ? "STACKED" : "CURRENT");
01438     foreach(lc, stmt->diag_items)
01439     {
01440         PLpgSQL_diag_item *diag_item = (PLpgSQL_diag_item *) lfirst(lc);
01441 
01442         if (lc != list_head(stmt->diag_items))
01443             printf(", ");
01444 
01445         printf("{var %d} = %s", diag_item->target,
01446                plpgsql_getdiag_kindname(diag_item->kind));
01447     }
01448     printf("\n");
01449 }
01450 
01451 static void
01452 dump_expr(PLpgSQL_expr *expr)
01453 {
01454     printf("'%s'", expr->query);
01455 }
01456 
01457 void
01458 plpgsql_dumptree(PLpgSQL_function *func)
01459 {
01460     int         i;
01461     PLpgSQL_datum *d;
01462 
01463     printf("\nExecution tree of successfully compiled PL/pgSQL function %s:\n",
01464            func->fn_signature);
01465 
01466     printf("\nFunction's data area:\n");
01467     for (i = 0; i < func->ndatums; i++)
01468     {
01469         d = func->datums[i];
01470 
01471         printf("    entry %d: ", i);
01472         switch (d->dtype)
01473         {
01474             case PLPGSQL_DTYPE_VAR:
01475                 {
01476                     PLpgSQL_var *var = (PLpgSQL_var *) d;
01477 
01478                     printf("VAR %-16s type %s (typoid %u) atttypmod %d\n",
01479                            var->refname, var->datatype->typname,
01480                            var->datatype->typoid,
01481                            var->datatype->atttypmod);
01482                     if (var->isconst)
01483                         printf("                                  CONSTANT\n");
01484                     if (var->notnull)
01485                         printf("                                  NOT NULL\n");
01486                     if (var->default_val != NULL)
01487                     {
01488                         printf("                                  DEFAULT ");
01489                         dump_expr(var->default_val);
01490                         printf("\n");
01491                     }
01492                     if (var->cursor_explicit_expr != NULL)
01493                     {
01494                         if (var->cursor_explicit_argrow >= 0)
01495                             printf("                                  CURSOR argument row %d\n", var->cursor_explicit_argrow);
01496 
01497                         printf("                                  CURSOR IS ");
01498                         dump_expr(var->cursor_explicit_expr);
01499                         printf("\n");
01500                     }
01501                 }
01502                 break;
01503             case PLPGSQL_DTYPE_ROW:
01504                 {
01505                     PLpgSQL_row *row = (PLpgSQL_row *) d;
01506                     int         i;
01507 
01508                     printf("ROW %-16s fields", row->refname);
01509                     for (i = 0; i < row->nfields; i++)
01510                     {
01511                         if (row->fieldnames[i])
01512                             printf(" %s=var %d", row->fieldnames[i],
01513                                    row->varnos[i]);
01514                     }
01515                     printf("\n");
01516                 }
01517                 break;
01518             case PLPGSQL_DTYPE_REC:
01519                 printf("REC %s\n", ((PLpgSQL_rec *) d)->refname);
01520                 break;
01521             case PLPGSQL_DTYPE_RECFIELD:
01522                 printf("RECFIELD %-16s of REC %d\n",
01523                        ((PLpgSQL_recfield *) d)->fieldname,
01524                        ((PLpgSQL_recfield *) d)->recparentno);
01525                 break;
01526             case PLPGSQL_DTYPE_ARRAYELEM:
01527                 printf("ARRAYELEM of VAR %d subscript ",
01528                        ((PLpgSQL_arrayelem *) d)->arrayparentno);
01529                 dump_expr(((PLpgSQL_arrayelem *) d)->subscript);
01530                 printf("\n");
01531                 break;
01532             default:
01533                 printf("??? unknown data type %d\n", d->dtype);
01534         }
01535     }
01536     printf("\nFunction's statements:\n");
01537 
01538     dump_indent = 0;
01539     printf("%3d:", func->action->lineno);
01540     dump_block(func->action);
01541     printf("\nEnd of execution tree of function %s\n\n", func->fn_signature);
01542     fflush(stdout);
01543 }