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