]> granicus.if.org Git - postgresql/blob - src/pl/plpgsql/src/pl_funcs.c
Fix plpgsql to not lookup block labels except in contexts where a block label
[postgresql] / src / pl / plpgsql / src / pl_funcs.c
1 /*-------------------------------------------------------------------------
2  *
3  * pl_funcs.c           - Misc functions for the PL/pgSQL
4  *                        procedural language
5  *
6  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.66 2007/11/27 19:58:44 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 #include "plpgsql.h"
17 #include "pl.tab.h"
18
19 #include <ctype.h>
20
21 #include "parser/scansup.h"
22
23
24 /* ----------
25  * Local variables for the namestack handling
26  * ----------
27  */
28 static PLpgSQL_ns *ns_current = NULL;
29 static bool ns_localmode = false;
30
31
32 /* ----------
33  * plpgsql_dstring_init                 Dynamic string initialization
34  * ----------
35  */
36 void
37 plpgsql_dstring_init(PLpgSQL_dstring *ds)
38 {
39         ds->value = palloc(ds->alloc = 512);
40         ds->used = 1;
41         ds->value[0] = '\0';
42 }
43
44
45 /* ----------
46  * plpgsql_dstring_free                 Dynamic string destruction
47  * ----------
48  */
49 void
50 plpgsql_dstring_free(PLpgSQL_dstring *ds)
51 {
52         pfree(ds->value);
53 }
54
55 static void
56 plpgsql_dstring_expand(PLpgSQL_dstring *ds, int needed)
57 {
58         /* Don't allow truncating the string */
59         Assert(needed > ds->alloc);
60         Assert(ds->used <= ds->alloc);
61
62         /* Might have to double more than once, if needed is large */
63         do
64         {
65                 ds->alloc *= 2;
66         } while (needed > ds->alloc);
67         ds->value = repalloc(ds->value, ds->alloc);
68 }
69
70 /* ----------
71  * plpgsql_dstring_append               Dynamic string extending
72  * ----------
73  */
74 void
75 plpgsql_dstring_append(PLpgSQL_dstring *ds, const char *str)
76 {
77         int                     len = strlen(str);
78         int                     needed = ds->used + len;
79
80         if (needed > ds->alloc)
81                 plpgsql_dstring_expand(ds, needed);
82
83         memcpy(&(ds->value[ds->used - 1]), str, len);
84         ds->used += len;
85         ds->value[ds->used - 1] = '\0';
86 }
87
88 /* ----------
89  * plpgsql_dstring_append_char  Append a single character
90  *                                                              to a dynamic string
91  * ----------
92  */
93 void
94 plpgsql_dstring_append_char(PLpgSQL_dstring *ds, char c)
95 {
96         if (ds->used == ds->alloc)
97                 plpgsql_dstring_expand(ds, ds->used + 1);
98
99         ds->value[ds->used - 1] = c;
100         ds->value[ds->used] = '\0';
101         ds->used++;
102 }
103
104
105 /* ----------
106  * plpgsql_dstring_get                  Dynamic string get value
107  * ----------
108  */
109 char *
110 plpgsql_dstring_get(PLpgSQL_dstring *ds)
111 {
112         return ds->value;
113 }
114
115
116 /* ----------
117  * plpgsql_ns_init                      Initialize the namestack
118  * ----------
119  */
120 void
121 plpgsql_ns_init(void)
122 {
123         ns_current = NULL;
124         ns_localmode = false;
125 }
126
127
128 /* ----------
129  * plpgsql_ns_setlocal                  Tell plpgsql_ns_lookup whether to
130  *                                      look into the current level only.
131  *
132  * This is a crock, but in the current design we need it because scan.l
133  * initiates name lookup, and the scanner does not know whether we are
134  * examining a name being declared in a DECLARE section.  For that case
135  * we only want to know if there is a conflicting name earlier in the
136  * same DECLARE section.  So the grammar must temporarily set local mode
137  * before scanning decl_varnames.
138  * ----------
139  */
140 bool
141 plpgsql_ns_setlocal(bool flag)
142 {
143         bool            oldstate;
144
145         oldstate = ns_localmode;
146         ns_localmode = flag;
147         return oldstate;
148 }
149
150
151 /* ----------
152  * plpgsql_ns_push                      Enter a new namestack level
153  * ----------
154  */
155 void
156 plpgsql_ns_push(const char *label)
157 {
158         PLpgSQL_ns *new;
159
160         if (label == NULL)
161                 label = "";
162
163         new = palloc0(sizeof(PLpgSQL_ns));
164         new->upper = ns_current;
165         ns_current = new;
166
167         plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, 0, label);
168 }
169
170
171 /* ----------
172  * plpgsql_ns_pop                       Return to the previous level
173  * ----------
174  */
175 void
176 plpgsql_ns_pop(void)
177 {
178         int                     i;
179         PLpgSQL_ns *old;
180
181         old = ns_current;
182         ns_current = old->upper;
183
184         for (i = 0; i < old->items_used; i++)
185                 pfree(old->items[i]);
186         pfree(old->items);
187         pfree(old);
188 }
189
190
191 /* ----------
192  * plpgsql_ns_additem                   Add an item to the current
193  *                                      namestack level
194  * ----------
195  */
196 void
197 plpgsql_ns_additem(int itemtype, int itemno, const char *name)
198 {
199         PLpgSQL_ns *ns = ns_current;
200         PLpgSQL_nsitem *nse;
201
202         Assert(name != NULL);
203
204         if (ns->items_used == ns->items_alloc)
205         {
206                 if (ns->items_alloc == 0)
207                 {
208                         ns->items_alloc = 32;
209                         ns->items = palloc(sizeof(PLpgSQL_nsitem *) * ns->items_alloc);
210                 }
211                 else
212                 {
213                         ns->items_alloc *= 2;
214                         ns->items = repalloc(ns->items,
215                                                                  sizeof(PLpgSQL_nsitem *) * ns->items_alloc);
216                 }
217         }
218
219         nse = palloc(sizeof(PLpgSQL_nsitem) + strlen(name));
220         nse->itemtype = itemtype;
221         nse->itemno = itemno;
222         strcpy(nse->name, name);
223         ns->items[ns->items_used++] = nse;
224 }
225
226
227 /* ----------
228  * plpgsql_ns_lookup                    Lookup an identifier in the namestack
229  *
230  * Note that this only searches for variables, not labels.
231  *
232  * name1 must be non-NULL.  Pass NULL for name2 and/or name3 if parsing a name
233  * with fewer than three components.
234  *
235  * If names_used isn't NULL, *names_used receives the number of names
236  * matched: 0 if no match, 1 if name1 matched an unqualified variable name,
237  * 2 if name1 and name2 matched a block label + variable name.
238  *
239  * Note that name3 is never directly matched to anything.  However, if it
240  * isn't NULL, we will disregard qualified matches to scalar variables.
241  * Similarly, if name2 isn't NULL, we disregard unqualified matches to
242  * scalar variables.
243  * ----------
244  */
245 PLpgSQL_nsitem *
246 plpgsql_ns_lookup(const char *name1, const char *name2, const char *name3,
247                                   int *names_used)
248 {
249         PLpgSQL_ns *ns;
250         int                     i;
251
252         /* Scan each level of the namestack */
253         for (ns = ns_current; ns != NULL; ns = ns->upper)
254         {
255                 /* Check for unqualified match to variable name */
256                 for (i = 1; i < ns->items_used; i++)
257                 {
258                         PLpgSQL_nsitem *nsitem = ns->items[i];
259
260                         if (strcmp(nsitem->name, name1) == 0)
261                         {
262                                 if (name2 == NULL ||
263                                         nsitem->itemtype != PLPGSQL_NSTYPE_VAR)
264                                 {
265                                         if (names_used)
266                                                 *names_used = 1;
267                                         return nsitem;
268                                 }
269                         }
270                 }
271
272                 /* Check for qualified match to variable name */
273                 if (name2 != NULL &&
274                         strcmp(ns->items[0]->name, name1) == 0)
275                 {
276                         for (i = 1; i < ns->items_used; i++)
277                         {
278                                 PLpgSQL_nsitem *nsitem = ns->items[i];
279
280                                 if (strcmp(nsitem->name, name2) == 0)
281                                 {
282                                         if (name3 == NULL ||
283                                                 nsitem->itemtype != PLPGSQL_NSTYPE_VAR)
284                                         {
285                                                 if (names_used)
286                                                         *names_used = 2;
287                                                 return nsitem;
288                                         }
289                                 }
290                         }
291                 }
292
293                 if (ns_localmode)
294                         break;                          /* do not look into upper levels */
295         }
296
297         /* This is just to suppress possibly-uninitialized-variable warnings */
298         if (names_used)
299                 *names_used = 0;
300         return NULL;                            /* No match found */
301 }
302
303
304 /* ----------
305  * plpgsql_ns_lookup_label              Lookup a label in the namestack
306  * ----------
307  */
308 PLpgSQL_nsitem *
309 plpgsql_ns_lookup_label(const char *name)
310 {
311         PLpgSQL_ns *ns;
312
313         for (ns = ns_current; ns != NULL; ns = ns->upper)
314         {
315                 if (strcmp(ns->items[0]->name, name) == 0)
316                         return ns->items[0];
317         }
318
319         return NULL;                            /* label not found */
320 }
321
322
323 /* ----------
324  * plpgsql_ns_rename                    Rename a namespace entry
325  * ----------
326  */
327 void
328 plpgsql_ns_rename(char *oldname, char *newname)
329 {
330         PLpgSQL_ns *ns;
331         PLpgSQL_nsitem *newitem;
332         int                     i;
333
334         /*
335          * Lookup name in the namestack
336          */
337         for (ns = ns_current; ns != NULL; ns = ns->upper)
338         {
339                 for (i = 1; i < ns->items_used; i++)
340                 {
341                         if (strcmp(ns->items[i]->name, oldname) == 0)
342                         {
343                                 newitem = palloc(sizeof(PLpgSQL_nsitem) + strlen(newname));
344                                 newitem->itemtype = ns->items[i]->itemtype;
345                                 newitem->itemno = ns->items[i]->itemno;
346                                 strcpy(newitem->name, newname);
347
348                                 pfree(oldname);
349                                 pfree(newname);
350
351                                 pfree(ns->items[i]);
352                                 ns->items[i] = newitem;
353                                 return;
354                         }
355                 }
356         }
357
358         ereport(ERROR,
359                         (errcode(ERRCODE_UNDEFINED_OBJECT),
360                          errmsg("there is no variable \"%s\" in the current block",
361                                         oldname)));
362 }
363
364
365 /* ----------
366  * plpgsql_convert_ident
367  *
368  * Convert a possibly-qualified identifier to internal form: handle
369  * double quotes, translate to lower case where not inside quotes,
370  * truncate to NAMEDATALEN.
371  *
372  * There may be several identifiers separated by dots and optional
373  * whitespace.  Each one is converted to a separate palloc'd string.
374  * The caller passes the expected number of identifiers, as well as
375  * a char* array to hold them.  It is an error if we find the wrong
376  * number of identifiers (cf grammar processing of fori_varname).
377  *
378  * NOTE: the input string has already been accepted by the flex lexer,
379  * so we don't need a heckuva lot of error checking here.
380  * ----------
381  */
382 void
383 plpgsql_convert_ident(const char *s, char **output, int numidents)
384 {
385         const char *sstart = s;
386         int                     identctr = 0;
387
388         /* Outer loop over identifiers */
389         while (*s)
390         {
391                 char       *curident;
392                 char       *cp;
393
394                 /* Process current identifier */
395
396                 if (*s == '"')
397                 {
398                         /* Quoted identifier: copy, collapsing out doubled quotes */
399
400                         curident = palloc(strlen(s) + 1);       /* surely enough room */
401                         cp = curident;
402                         s++;
403                         while (*s)
404                         {
405                                 if (*s == '"')
406                                 {
407                                         if (s[1] != '"')
408                                                 break;
409                                         s++;
410                                 }
411                                 *cp++ = *s++;
412                         }
413                         if (*s != '"')          /* should not happen if lexer checked */
414                                 ereport(ERROR,
415                                                 (errcode(ERRCODE_SYNTAX_ERROR),
416                                                  errmsg("unterminated \" in name: %s", sstart)));
417                         s++;
418                         *cp = '\0';
419                         /* Truncate to NAMEDATALEN */
420                         truncate_identifier(curident, cp - curident, false);
421                 }
422                 else
423                 {
424                         /* Normal identifier: extends till dot or whitespace */
425                         const char *thisstart = s;
426
427                         while (*s && *s != '.' && !scanner_isspace(*s))
428                                 s++;
429                         /* Downcase and truncate to NAMEDATALEN */
430                         curident = downcase_truncate_identifier(thisstart, s - thisstart,
431                                                                                                         false);
432                 }
433
434                 /* Pass ident to caller */
435                 if (identctr < numidents)
436                         output[identctr++] = curident;
437                 else
438                         ereport(ERROR,
439                                         (errcode(ERRCODE_SYNTAX_ERROR),
440                                          errmsg("qualified identifier cannot be used here: %s",
441                                                         sstart)));
442
443                 /* If not done, skip whitespace, dot, whitespace */
444                 if (*s)
445                 {
446                         while (*s && scanner_isspace(*s))
447                                 s++;
448                         if (*s++ != '.')
449                                 elog(ERROR, "expected dot between identifiers: %s", sstart);
450                         while (*s && scanner_isspace(*s))
451                                 s++;
452                         if (*s == '\0')
453                                 elog(ERROR, "expected another identifier: %s", sstart);
454                 }
455         }
456
457         if (identctr != numidents)
458                 elog(ERROR, "improperly qualified identifier: %s",
459                          sstart);
460 }
461
462
463 /*
464  * Statement type as a string, for use in error messages etc.
465  */
466 const char *
467 plpgsql_stmt_typename(PLpgSQL_stmt *stmt)
468 {
469         switch (stmt->cmd_type)
470         {
471                 case PLPGSQL_STMT_BLOCK:
472                         return _("statement block");
473                 case PLPGSQL_STMT_ASSIGN:
474                         return _("assignment");
475                 case PLPGSQL_STMT_IF:
476                         return "IF";
477                 case PLPGSQL_STMT_LOOP:
478                         return "LOOP";
479                 case PLPGSQL_STMT_WHILE:
480                         return "WHILE";
481                 case PLPGSQL_STMT_FORI:
482                         return _("FOR with integer loop variable");
483                 case PLPGSQL_STMT_FORS:
484                         return _("FOR over SELECT rows");
485                 case PLPGSQL_STMT_EXIT:
486                         return "EXIT";
487                 case PLPGSQL_STMT_RETURN:
488                         return "RETURN";
489                 case PLPGSQL_STMT_RETURN_NEXT:
490                         return "RETURN NEXT";
491                 case PLPGSQL_STMT_RETURN_QUERY:
492                         return "RETURN QUERY";
493                 case PLPGSQL_STMT_RAISE:
494                         return "RAISE";
495                 case PLPGSQL_STMT_EXECSQL:
496                         return _("SQL statement");
497                 case PLPGSQL_STMT_DYNEXECUTE:
498                         return _("EXECUTE statement");
499                 case PLPGSQL_STMT_DYNFORS:
500                         return _("FOR over EXECUTE statement");
501                 case PLPGSQL_STMT_GETDIAG:
502                         return "GET DIAGNOSTICS";
503                 case PLPGSQL_STMT_OPEN:
504                         return "OPEN";
505                 case PLPGSQL_STMT_FETCH:
506                         return "FETCH";
507                 case PLPGSQL_STMT_CLOSE:
508                         return "CLOSE";
509                 case PLPGSQL_STMT_PERFORM:
510                         return "PERFORM";
511         }
512
513         return "unknown";
514 }
515
516
517 /**********************************************************************
518  * Debug functions for analyzing the compiled code
519  **********************************************************************/
520 static int      dump_indent;
521
522 static void dump_ind(void);
523 static void dump_stmt(PLpgSQL_stmt *stmt);
524 static void dump_block(PLpgSQL_stmt_block *block);
525 static void dump_assign(PLpgSQL_stmt_assign *stmt);
526 static void dump_if(PLpgSQL_stmt_if *stmt);
527 static void dump_loop(PLpgSQL_stmt_loop *stmt);
528 static void dump_while(PLpgSQL_stmt_while *stmt);
529 static void dump_fori(PLpgSQL_stmt_fori *stmt);
530 static void dump_fors(PLpgSQL_stmt_fors *stmt);
531 static void dump_exit(PLpgSQL_stmt_exit *stmt);
532 static void dump_return(PLpgSQL_stmt_return *stmt);
533 static void dump_return_next(PLpgSQL_stmt_return_next *stmt);
534 static void dump_return_query(PLpgSQL_stmt_return_query *stmt);
535 static void dump_raise(PLpgSQL_stmt_raise *stmt);
536 static void dump_execsql(PLpgSQL_stmt_execsql *stmt);
537 static void dump_dynexecute(PLpgSQL_stmt_dynexecute *stmt);
538 static void dump_dynfors(PLpgSQL_stmt_dynfors *stmt);
539 static void dump_getdiag(PLpgSQL_stmt_getdiag *stmt);
540 static void dump_open(PLpgSQL_stmt_open *stmt);
541 static void dump_fetch(PLpgSQL_stmt_fetch *stmt);
542 static void dump_cursor_direction(PLpgSQL_stmt_fetch *stmt);
543 static void dump_close(PLpgSQL_stmt_close *stmt);
544 static void dump_perform(PLpgSQL_stmt_perform *stmt);
545 static void dump_expr(PLpgSQL_expr *expr);
546
547
548 static void
549 dump_ind(void)
550 {
551         int                     i;
552
553         for (i = 0; i < dump_indent; i++)
554                 printf(" ");
555 }
556
557 static void
558 dump_stmt(PLpgSQL_stmt *stmt)
559 {
560         printf("%3d:", stmt->lineno);
561         switch (stmt->cmd_type)
562         {
563                 case PLPGSQL_STMT_BLOCK:
564                         dump_block((PLpgSQL_stmt_block *) stmt);
565                         break;
566                 case PLPGSQL_STMT_ASSIGN:
567                         dump_assign((PLpgSQL_stmt_assign *) stmt);
568                         break;
569                 case PLPGSQL_STMT_IF:
570                         dump_if((PLpgSQL_stmt_if *) stmt);
571                         break;
572                 case PLPGSQL_STMT_LOOP:
573                         dump_loop((PLpgSQL_stmt_loop *) stmt);
574                         break;
575                 case PLPGSQL_STMT_WHILE:
576                         dump_while((PLpgSQL_stmt_while *) stmt);
577                         break;
578                 case PLPGSQL_STMT_FORI:
579                         dump_fori((PLpgSQL_stmt_fori *) stmt);
580                         break;
581                 case PLPGSQL_STMT_FORS:
582                         dump_fors((PLpgSQL_stmt_fors *) stmt);
583                         break;
584                 case PLPGSQL_STMT_EXIT:
585                         dump_exit((PLpgSQL_stmt_exit *) stmt);
586                         break;
587                 case PLPGSQL_STMT_RETURN:
588                         dump_return((PLpgSQL_stmt_return *) stmt);
589                         break;
590                 case PLPGSQL_STMT_RETURN_NEXT:
591                         dump_return_next((PLpgSQL_stmt_return_next *) stmt);
592                         break;
593                 case PLPGSQL_STMT_RETURN_QUERY:
594                         dump_return_query((PLpgSQL_stmt_return_query *) stmt);
595                         break;
596                 case PLPGSQL_STMT_RAISE:
597                         dump_raise((PLpgSQL_stmt_raise *) stmt);
598                         break;
599                 case PLPGSQL_STMT_EXECSQL:
600                         dump_execsql((PLpgSQL_stmt_execsql *) stmt);
601                         break;
602                 case PLPGSQL_STMT_DYNEXECUTE:
603                         dump_dynexecute((PLpgSQL_stmt_dynexecute *) stmt);
604                         break;
605                 case PLPGSQL_STMT_DYNFORS:
606                         dump_dynfors((PLpgSQL_stmt_dynfors *) stmt);
607                         break;
608                 case PLPGSQL_STMT_GETDIAG:
609                         dump_getdiag((PLpgSQL_stmt_getdiag *) stmt);
610                         break;
611                 case PLPGSQL_STMT_OPEN:
612                         dump_open((PLpgSQL_stmt_open *) stmt);
613                         break;
614                 case PLPGSQL_STMT_FETCH:
615                         dump_fetch((PLpgSQL_stmt_fetch *) stmt);
616                         break;
617                 case PLPGSQL_STMT_CLOSE:
618                         dump_close((PLpgSQL_stmt_close *) stmt);
619                         break;
620                 case PLPGSQL_STMT_PERFORM:
621                         dump_perform((PLpgSQL_stmt_perform *) stmt);
622                         break;
623                 default:
624                         elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
625                         break;
626         }
627 }
628
629 static void
630 dump_stmts(List *stmts)
631 {
632         ListCell   *s;
633
634         dump_indent += 2;
635         foreach(s, stmts)
636                 dump_stmt((PLpgSQL_stmt *) lfirst(s));
637         dump_indent -= 2;
638 }
639
640 static void
641 dump_block(PLpgSQL_stmt_block *block)
642 {
643         char       *name;
644
645         if (block->label == NULL)
646                 name = "*unnamed*";
647         else
648                 name = block->label;
649
650         dump_ind();
651         printf("BLOCK <<%s>>\n", name);
652
653         dump_stmts(block->body);
654
655         if (block->exceptions)
656         {
657                 ListCell   *e;
658
659                 foreach(e, block->exceptions->exc_list)
660                 {
661                         PLpgSQL_exception *exc = (PLpgSQL_exception *) lfirst(e);
662                         PLpgSQL_condition *cond;
663
664                         dump_ind();
665                         printf("    EXCEPTION WHEN ");
666                         for (cond = exc->conditions; cond; cond = cond->next)
667                         {
668                                 if (cond != exc->conditions)
669                                         printf(" OR ");
670                                 printf("%s", cond->condname);
671                         }
672                         printf(" THEN\n");
673                         dump_stmts(exc->action);
674                 }
675         }
676
677         dump_ind();
678         printf("    END -- %s\n", name);
679 }
680
681 static void
682 dump_assign(PLpgSQL_stmt_assign *stmt)
683 {
684         dump_ind();
685         printf("ASSIGN var %d := ", stmt->varno);
686         dump_expr(stmt->expr);
687         printf("\n");
688 }
689
690 static void
691 dump_if(PLpgSQL_stmt_if *stmt)
692 {
693         dump_ind();
694         printf("IF ");
695         dump_expr(stmt->cond);
696         printf(" THEN\n");
697
698         dump_stmts(stmt->true_body);
699
700         if (stmt->false_body != NIL)
701         {
702                 dump_ind();
703                 printf("    ELSE\n");
704                 dump_stmts(stmt->false_body);
705         }
706
707         dump_ind();
708         printf("    ENDIF\n");
709 }
710
711 static void
712 dump_loop(PLpgSQL_stmt_loop *stmt)
713 {
714         dump_ind();
715         printf("LOOP\n");
716
717         dump_stmts(stmt->body);
718
719         dump_ind();
720         printf("    ENDLOOP\n");
721 }
722
723 static void
724 dump_while(PLpgSQL_stmt_while *stmt)
725 {
726         dump_ind();
727         printf("WHILE ");
728         dump_expr(stmt->cond);
729         printf("\n");
730
731         dump_stmts(stmt->body);
732
733         dump_ind();
734         printf("    ENDWHILE\n");
735 }
736
737 static void
738 dump_fori(PLpgSQL_stmt_fori *stmt)
739 {
740         dump_ind();
741         printf("FORI %s %s\n", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL");
742
743         dump_indent += 2;
744         dump_ind();
745         printf("    lower = ");
746         dump_expr(stmt->lower);
747         printf("\n");
748         dump_ind();
749         printf("    upper = ");
750         dump_expr(stmt->upper);
751         printf("\n");
752         dump_ind();
753         printf("    step = ");
754         dump_expr(stmt->step);
755         printf("\n");
756         dump_indent -= 2;
757
758         dump_stmts(stmt->body);
759
760         dump_ind();
761         printf("    ENDFORI\n");
762 }
763
764 static void
765 dump_fors(PLpgSQL_stmt_fors *stmt)
766 {
767         dump_ind();
768         printf("FORS %s ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
769         dump_expr(stmt->query);
770         printf("\n");
771
772         dump_stmts(stmt->body);
773
774         dump_ind();
775         printf("    ENDFORS\n");
776 }
777
778 static void
779 dump_open(PLpgSQL_stmt_open *stmt)
780 {
781         dump_ind();
782         printf("OPEN curvar=%d\n", stmt->curvar);
783
784         dump_indent += 2;
785         if (stmt->argquery != NULL)
786         {
787                 dump_ind();
788                 printf("  arguments = '");
789                 dump_expr(stmt->argquery);
790                 printf("'\n");
791         }
792         if (stmt->query != NULL)
793         {
794                 dump_ind();
795                 printf("  query = '");
796                 dump_expr(stmt->query);
797                 printf("'\n");
798         }
799         if (stmt->dynquery != NULL)
800         {
801                 dump_ind();
802                 printf("  execute = '");
803                 dump_expr(stmt->dynquery);
804                 printf("'\n");
805         }
806         dump_indent -= 2;
807
808 }
809
810 static void
811 dump_fetch(PLpgSQL_stmt_fetch *stmt)
812 {
813         dump_ind();
814
815         if (!stmt->is_move)
816         {
817                 printf("FETCH curvar=%d\n", stmt->curvar);
818                 dump_cursor_direction(stmt);
819
820                 dump_indent += 2;
821                 if (stmt->rec != NULL)
822                 {
823                         dump_ind();
824                         printf("    target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
825                 }
826                 if (stmt->row != NULL)
827                 {
828                         dump_ind();
829                         printf("    target = %d %s\n", stmt->row->rowno, stmt->row->refname);
830                 }
831                 dump_indent -= 2;
832         }
833         else
834         {
835                 printf("MOVE curvar=%d\n", stmt->curvar);
836                 dump_cursor_direction(stmt);
837         }
838 }
839
840 static void
841 dump_cursor_direction(PLpgSQL_stmt_fetch *stmt)
842 {
843         dump_indent += 2;
844         dump_ind();
845         switch (stmt->direction)
846         {
847                 case FETCH_FORWARD:
848                         printf("    FORWARD ");
849                         break;
850                 case FETCH_BACKWARD:
851                         printf("    BACKWARD ");
852                         break;
853                 case FETCH_ABSOLUTE:
854                         printf("    ABSOLUTE ");
855                         break;
856                 case FETCH_RELATIVE:
857                         printf("    RELATIVE ");
858                         break;
859                 default:
860                         printf("??? unknown cursor direction %d", stmt->direction);
861         }
862
863         if (stmt->expr)
864         {
865                 dump_expr(stmt->expr);
866                 printf("\n");
867         }
868         else
869                 printf("%d\n", stmt->how_many);
870
871         dump_indent -= 2;
872 }
873
874 static void
875 dump_close(PLpgSQL_stmt_close *stmt)
876 {
877         dump_ind();
878         printf("CLOSE curvar=%d\n", stmt->curvar);
879 }
880
881 static void
882 dump_perform(PLpgSQL_stmt_perform *stmt)
883 {
884         dump_ind();
885         printf("PERFORM expr = ");
886         dump_expr(stmt->expr);
887         printf("\n");
888 }
889
890 static void
891 dump_exit(PLpgSQL_stmt_exit *stmt)
892 {
893         dump_ind();
894         printf("%s", stmt->is_exit ? "EXIT" : "CONTINUE");
895         if (stmt->label != NULL)
896                 printf(" label='%s'", stmt->label);
897         if (stmt->cond != NULL)
898         {
899                 printf(" WHEN ");
900                 dump_expr(stmt->cond);
901         }
902         printf("\n");
903 }
904
905 static void
906 dump_return(PLpgSQL_stmt_return *stmt)
907 {
908         dump_ind();
909         printf("RETURN ");
910         if (stmt->retvarno >= 0)
911                 printf("variable %d", stmt->retvarno);
912         else if (stmt->expr != NULL)
913                 dump_expr(stmt->expr);
914         else
915                 printf("NULL");
916         printf("\n");
917 }
918
919 static void
920 dump_return_next(PLpgSQL_stmt_return_next *stmt)
921 {
922         dump_ind();
923         printf("RETURN NEXT ");
924         if (stmt->retvarno >= 0)
925                 printf("variable %d", stmt->retvarno);
926         else if (stmt->expr != NULL)
927                 dump_expr(stmt->expr);
928         else
929                 printf("NULL");
930         printf("\n");
931 }
932
933 static void
934 dump_return_query(PLpgSQL_stmt_return_query *stmt)
935 {
936         dump_ind();
937         printf("RETURN QUERY ");
938         dump_expr(stmt->query);
939         printf("\n");
940 }
941
942 static void
943 dump_raise(PLpgSQL_stmt_raise *stmt)
944 {
945         ListCell   *lc;
946         int                     i = 0;
947
948         dump_ind();
949         printf("RAISE '%s'\n", stmt->message);
950         dump_indent += 2;
951         foreach(lc, stmt->params)
952         {
953                 dump_ind();
954                 printf("    parameter %d: ", i++);
955                 dump_expr((PLpgSQL_expr *) lfirst(lc));
956                 printf("\n");
957         }
958         dump_indent -= 2;
959 }
960
961 static void
962 dump_execsql(PLpgSQL_stmt_execsql *stmt)
963 {
964         dump_ind();
965         printf("EXECSQL ");
966         dump_expr(stmt->sqlstmt);
967         printf("\n");
968
969         dump_indent += 2;
970         if (stmt->rec != NULL)
971         {
972                 dump_ind();
973                 printf("    INTO%s target = %d %s\n",
974                            stmt->strict ? " STRICT" : "",
975                            stmt->rec->recno, stmt->rec->refname);
976         }
977         if (stmt->row != NULL)
978         {
979                 dump_ind();
980                 printf("    INTO%s target = %d %s\n",
981                            stmt->strict ? " STRICT" : "",
982                            stmt->row->rowno, stmt->row->refname);
983         }
984         dump_indent -= 2;
985 }
986
987 static void
988 dump_dynexecute(PLpgSQL_stmt_dynexecute *stmt)
989 {
990         dump_ind();
991         printf("EXECUTE ");
992         dump_expr(stmt->query);
993         printf("\n");
994
995         dump_indent += 2;
996         if (stmt->rec != NULL)
997         {
998                 dump_ind();
999                 printf("    INTO%s target = %d %s\n",
1000                            stmt->strict ? " STRICT" : "",
1001                            stmt->rec->recno, stmt->rec->refname);
1002         }
1003         if (stmt->row != NULL)
1004         {
1005                 dump_ind();
1006                 printf("    INTO%s target = %d %s\n",
1007                            stmt->strict ? " STRICT" : "",
1008                            stmt->row->rowno, stmt->row->refname);
1009         }
1010         dump_indent -= 2;
1011 }
1012
1013 static void
1014 dump_dynfors(PLpgSQL_stmt_dynfors *stmt)
1015 {
1016         dump_ind();
1017         printf("FORS %s EXECUTE ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
1018         dump_expr(stmt->query);
1019         printf("\n");
1020
1021         dump_stmts(stmt->body);
1022
1023         dump_ind();
1024         printf("    ENDFORS\n");
1025 }
1026
1027 static void
1028 dump_getdiag(PLpgSQL_stmt_getdiag *stmt)
1029 {
1030         ListCell   *lc;
1031
1032         dump_ind();
1033         printf("GET DIAGNOSTICS ");
1034         foreach(lc, stmt->diag_items)
1035         {
1036                 PLpgSQL_diag_item *diag_item = (PLpgSQL_diag_item *) lfirst(lc);
1037
1038                 if (lc != list_head(stmt->diag_items))
1039                         printf(", ");
1040
1041                 printf("{var %d} = ", diag_item->target);
1042
1043                 switch (diag_item->kind)
1044                 {
1045                         case PLPGSQL_GETDIAG_ROW_COUNT:
1046                                 printf("ROW_COUNT");
1047                                 break;
1048
1049                         case PLPGSQL_GETDIAG_RESULT_OID:
1050                                 printf("RESULT_OID");
1051                                 break;
1052
1053                         default:
1054                                 printf("???");
1055                                 break;
1056                 }
1057         }
1058         printf("\n");
1059 }
1060
1061 static void
1062 dump_expr(PLpgSQL_expr *expr)
1063 {
1064         int                     i;
1065
1066         printf("'%s", expr->query);
1067         if (expr->nparams > 0)
1068         {
1069                 printf(" {");
1070                 for (i = 0; i < expr->nparams; i++)
1071                 {
1072                         if (i > 0)
1073                                 printf(", ");
1074                         printf("$%d=%d", i + 1, expr->params[i]);
1075                 }
1076                 printf("}");
1077         }
1078         printf("'");
1079 }
1080
1081 void
1082 plpgsql_dumptree(PLpgSQL_function *func)
1083 {
1084         int                     i;
1085         PLpgSQL_datum *d;
1086
1087         printf("\nExecution tree of successfully compiled PL/pgSQL function %s:\n",
1088                    func->fn_name);
1089
1090         printf("\nFunction's data area:\n");
1091         for (i = 0; i < func->ndatums; i++)
1092         {
1093                 d = func->datums[i];
1094
1095                 printf("    entry %d: ", i);
1096                 switch (d->dtype)
1097                 {
1098                         case PLPGSQL_DTYPE_VAR:
1099                                 {
1100                                         PLpgSQL_var *var = (PLpgSQL_var *) d;
1101
1102                                         printf("VAR %-16s type %s (typoid %u) atttypmod %d\n",
1103                                                    var->refname, var->datatype->typname,
1104                                                    var->datatype->typoid,
1105                                                    var->datatype->atttypmod);
1106                                         if (var->isconst)
1107                                                 printf("                                  CONSTANT\n");
1108                                         if (var->notnull)
1109                                                 printf("                                  NOT NULL\n");
1110                                         if (var->default_val != NULL)
1111                                         {
1112                                                 printf("                                  DEFAULT ");
1113                                                 dump_expr(var->default_val);
1114                                                 printf("\n");
1115                                         }
1116                                         if (var->cursor_explicit_expr != NULL)
1117                                         {
1118                                                 if (var->cursor_explicit_argrow >= 0)
1119                                                         printf("                                  CURSOR argument row %d\n", var->cursor_explicit_argrow);
1120
1121                                                 printf("                                  CURSOR IS ");
1122                                                 dump_expr(var->cursor_explicit_expr);
1123                                                 printf("\n");
1124                                         }
1125                                 }
1126                                 break;
1127                         case PLPGSQL_DTYPE_ROW:
1128                                 {
1129                                         PLpgSQL_row *row = (PLpgSQL_row *) d;
1130                                         int                     i;
1131
1132                                         printf("ROW %-16s fields", row->refname);
1133                                         for (i = 0; i < row->nfields; i++)
1134                                         {
1135                                                 if (row->fieldnames[i])
1136                                                         printf(" %s=var %d", row->fieldnames[i],
1137                                                                    row->varnos[i]);
1138                                         }
1139                                         printf("\n");
1140                                 }
1141                                 break;
1142                         case PLPGSQL_DTYPE_REC:
1143                                 printf("REC %s\n", ((PLpgSQL_rec *) d)->refname);
1144                                 break;
1145                         case PLPGSQL_DTYPE_RECFIELD:
1146                                 printf("RECFIELD %-16s of REC %d\n",
1147                                            ((PLpgSQL_recfield *) d)->fieldname,
1148                                            ((PLpgSQL_recfield *) d)->recparentno);
1149                                 break;
1150                         case PLPGSQL_DTYPE_ARRAYELEM:
1151                                 printf("ARRAYELEM of VAR %d subscript ",
1152                                            ((PLpgSQL_arrayelem *) d)->arrayparentno);
1153                                 dump_expr(((PLpgSQL_arrayelem *) d)->subscript);
1154                                 printf("\n");
1155                                 break;
1156                         case PLPGSQL_DTYPE_TRIGARG:
1157                                 printf("TRIGARG ");
1158                                 dump_expr(((PLpgSQL_trigarg *) d)->argnum);
1159                                 printf("\n");
1160                                 break;
1161                         default:
1162                                 printf("??? unknown data type %d\n", d->dtype);
1163                 }
1164         }
1165         printf("\nFunction's statements:\n");
1166
1167         dump_indent = 0;
1168         printf("%3d:", func->action->lineno);
1169         dump_block(func->action);
1170         printf("\nEnd of execution tree of function %s\n\n", func->fn_name);
1171         fflush(stdout);
1172 }