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