]> granicus.if.org Git - postgresql/blob - src/pl/plpgsql/src/pl_funcs.c
Cosmetic PL/PgSQL fix: declare the second parameter plpgsql_dstring_append
[postgresql] / src / pl / plpgsql / src / pl_funcs.c
1 /**********************************************************************
2  * pl_funcs.c           - Misc functins for the PL/pgSQL
3  *                        procedural language
4  *
5  * IDENTIFICATION
6  *        $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.37 2004/09/14 23:46:46 neilc Exp $
7  *
8  *        This software is copyrighted by Jan Wieck - Hamburg.
9  *
10  *        The author hereby grants permission  to  use,  copy,  modify,
11  *        distribute,  and      license this software and its documentation
12  *        for any purpose, provided that existing copyright notices are
13  *        retained      in      all  copies  and  that  this notice is included
14  *        verbatim in any distributions. No written agreement, license,
15  *        or  royalty  fee      is required for any of the authorized uses.
16  *        Modifications to this software may be  copyrighted  by  their
17  *        author  and  need  not  follow  the licensing terms described
18  *        here, provided that the new terms are  clearly  indicated  on
19  *        the first page of each file where they apply.
20  *
21  *        IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY
22  *        PARTY  FOR  DIRECT,   INDIRECT,       SPECIAL,   INCIDENTAL,   OR
23  *        CONSEQUENTIAL   DAMAGES  ARISING      OUT  OF  THE  USE  OF  THIS
24  *        SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
25  *        IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
26  *        DAMAGE.
27  *
28  *        THE  AUTHOR  AND      DISTRIBUTORS  SPECIFICALLY       DISCLAIM       ANY
29  *        WARRANTIES,  INCLUDING,  BUT  NOT  LIMITED  TO,  THE  IMPLIED
30  *        WARRANTIES  OF  MERCHANTABILITY,      FITNESS  FOR  A  PARTICULAR
31  *        PURPOSE,      AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON
32  *        AN "AS IS" BASIS, AND THE AUTHOR      AND  DISTRIBUTORS  HAVE  NO
33  *        OBLIGATION   TO       PROVIDE   MAINTENANCE,   SUPPORT,  UPDATES,
34  *        ENHANCEMENTS, OR MODIFICATIONS.
35  *
36  **********************************************************************/
37
38 #include "plpgsql.h"
39 #include "pl.tab.h"
40
41 #include <ctype.h>
42
43 #include "parser/scansup.h"
44
45
46 /* ----------
47  * Local variables for the namestack handling
48  * ----------
49  */
50 static PLpgSQL_ns *ns_current = NULL;
51 static bool ns_localmode = false;
52
53
54 /* ----------
55  * plpgsql_dstring_init                 Dynamic string initialization
56  * ----------
57  */
58 void
59 plpgsql_dstring_init(PLpgSQL_dstring *ds)
60 {
61         ds->value = palloc(ds->alloc = 512);
62         ds->used = 0;
63         ds->value[0] = '\0';
64 }
65
66
67 /* ----------
68  * plpgsql_dstring_free                 Dynamic string destruction
69  * ----------
70  */
71 void
72 plpgsql_dstring_free(PLpgSQL_dstring *ds)
73 {
74         pfree(ds->value);
75 }
76
77
78 /* ----------
79  * plpgsql_dstring_append               Dynamic string extending
80  * ----------
81  */
82 void
83 plpgsql_dstring_append(PLpgSQL_dstring *ds, const char *str)
84 {
85         int                     len = strlen(str);
86         int                     needed = ds->used + len + 1;
87
88         if (needed > ds->alloc)
89         {
90                 /* might have to double more than once, if len is large */
91                 do
92                 {
93                         ds->alloc *= 2;
94                 } while (needed > ds->alloc);
95                 ds->value = repalloc(ds->value, ds->alloc);
96         }
97
98         strcpy(&(ds->value[ds->used]), str);
99         ds->used += len;
100 }
101
102
103 /* ----------
104  * plpgsql_dstring_get                  Dynamic string get value
105  * ----------
106  */
107 char *
108 plpgsql_dstring_get(PLpgSQL_dstring *ds)
109 {
110         return ds->value;
111 }
112
113
114 /* ----------
115  * plpgsql_ns_init                      Initialize the namestack
116  * ----------
117  */
118 void
119 plpgsql_ns_init(void)
120 {
121         ns_current = NULL;
122         ns_localmode = false;
123 }
124
125
126 /* ----------
127  * plpgsql_ns_setlocal                  Tell plpgsql_ns_lookup to or to
128  *                                      not look into the current level
129  *                                      only.
130  * ----------
131  */
132 bool
133 plpgsql_ns_setlocal(bool flag)
134 {
135         bool            oldstate;
136
137         oldstate = ns_localmode;
138         ns_localmode = flag;
139         return oldstate;
140 }
141
142
143 /* ----------
144  * plpgsql_ns_push                      Enter a new namestack level
145  * ----------
146  */
147 void
148 plpgsql_ns_push(char *label)
149 {
150         PLpgSQL_ns *new;
151
152         if (label == NULL)
153                 label = "";
154
155         new = palloc(sizeof(PLpgSQL_ns));
156         memset(new, 0, sizeof(PLpgSQL_ns));
157         new->upper = ns_current;
158         ns_current = new;
159
160         plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, 0, label);
161 }
162
163
164 /* ----------
165  * plpgsql_ns_pop                       Return to the previous level
166  * ----------
167  */
168 void
169 plpgsql_ns_pop()
170 {
171         int                     i;
172         PLpgSQL_ns *old;
173
174         old = ns_current;
175         ns_current = old->upper;
176
177         for (i = 0; i < old->items_used; i++)
178                 pfree(old->items[i]);
179         pfree(old->items);
180         pfree(old);
181 }
182
183
184 /* ----------
185  * plpgsql_ns_additem                   Add an item to the current
186  *                                      namestack level
187  * ----------
188  */
189 void
190 plpgsql_ns_additem(int itemtype, int itemno, char *name)
191 {
192         PLpgSQL_ns *ns = ns_current;
193         PLpgSQL_nsitem *nse;
194
195         Assert(name != NULL);
196
197         if (ns->items_used == ns->items_alloc)
198         {
199                 if (ns->items_alloc == 0)
200                 {
201                         ns->items_alloc = 32;
202                         ns->items = palloc(sizeof(PLpgSQL_nsitem *) * ns->items_alloc);
203                 }
204                 else
205                 {
206                         ns->items_alloc *= 2;
207                         ns->items = repalloc(ns->items,
208                                                          sizeof(PLpgSQL_nsitem *) * ns->items_alloc);
209                 }
210         }
211
212         nse = palloc(sizeof(PLpgSQL_nsitem) + strlen(name));
213         nse->itemtype = itemtype;
214         nse->itemno = itemno;
215         strcpy(nse->name, name);
216         ns->items[ns->items_used++] = nse;
217 }
218
219
220 /* ----------
221  * plpgsql_ns_lookup                    Lookup for a word in the namestack
222  * ----------
223  */
224 PLpgSQL_nsitem *
225 plpgsql_ns_lookup(char *name, char *label)
226 {
227         PLpgSQL_ns *ns;
228         int                     i;
229
230         /*
231          * If a label is specified, lookup only in that
232          */
233         if (label != NULL)
234         {
235                 for (ns = ns_current; ns != NULL; ns = ns->upper)
236                 {
237                         if (!strcmp(ns->items[0]->name, label))
238                         {
239                                 for (i = 1; i < ns->items_used; i++)
240                                 {
241                                         if (!strcmp(ns->items[i]->name, name))
242                                                 return ns->items[i];
243                                 }
244                                 return NULL;    /* name not found in specified label */
245                         }
246                 }
247                 return NULL;                    /* label not found */
248         }
249
250         /*
251          * No label given, lookup for visible labels ignoring localmode
252          */
253         for (ns = ns_current; ns != NULL; ns = ns->upper)
254         {
255                 if (!strcmp(ns->items[0]->name, name))
256                         return ns->items[0];
257         }
258
259         /*
260          * Finally lookup name in the namestack
261          */
262         for (ns = ns_current; ns != NULL; ns = ns->upper)
263         {
264                 for (i = 1; i < ns->items_used; i++)
265                 {
266                         if (!strcmp(ns->items[i]->name, name))
267                                 return ns->items[i];
268                 }
269                 if (ns_localmode)
270                         return NULL;            /* name not found in current namespace */
271         }
272
273         return NULL;
274 }
275
276
277 /* ----------
278  * plpgsql_ns_rename                    Rename a namespace entry
279  * ----------
280  */
281 void
282 plpgsql_ns_rename(char *oldname, char *newname)
283 {
284         PLpgSQL_ns *ns;
285         PLpgSQL_nsitem *newitem;
286         int                     i;
287
288         /*
289          * Lookup in the current namespace only
290          */
291
292         /*
293          * Lookup name in the namestack
294          */
295         for (ns = ns_current; ns != NULL; ns = ns->upper)
296         {
297                 for (i = 1; i < ns->items_used; i++)
298                 {
299                         if (!strcmp(ns->items[i]->name, oldname))
300                         {
301                                 newitem = palloc(sizeof(PLpgSQL_nsitem) + strlen(newname));
302                                 newitem->itemtype = ns->items[i]->itemtype;
303                                 newitem->itemno = ns->items[i]->itemno;
304                                 strcpy(newitem->name, newname);
305
306                                 pfree(oldname);
307                                 pfree(newname);
308
309                                 pfree(ns->items[i]);
310                                 ns->items[i] = newitem;
311                                 return;
312                         }
313                 }
314         }
315
316         ereport(ERROR,
317                         (errcode(ERRCODE_UNDEFINED_OBJECT),
318                          errmsg("there is no variable \"%s\" in the current block",
319                                         oldname)));
320 }
321
322
323 /* ----------
324  * plpgsql_convert_ident
325  *
326  * Convert a possibly-qualified identifier to internal form: handle
327  * double quotes, translate to lower case where not inside quotes,
328  * truncate to NAMEDATALEN.
329  *
330  * There may be several identifiers separated by dots and optional
331  * whitespace.  Each one is converted to a separate palloc'd string.
332  * The caller passes the expected number of identifiers, as well as
333  * a char* array to hold them.  It is an error if we find the wrong
334  * number of identifiers (cf grammar processing of fori_varname).
335  *
336  * NOTE: the input string has already been accepted by the flex lexer,
337  * so we don't need a heckuva lot of error checking here.
338  * ----------
339  */
340 void
341 plpgsql_convert_ident(const char *s, char **output, int numidents)
342 {
343         const char *sstart = s;
344         int                     identctr = 0;
345
346         /* Outer loop over identifiers */
347         while (*s)
348         {
349                 char       *curident;
350                 char       *cp;
351
352                 /* Process current identifier */
353
354                 if (*s == '"')
355                 {
356                         /* Quoted identifier: copy, collapsing out doubled quotes */
357
358                         curident = palloc(strlen(s) + 1);       /* surely enough room */
359                         cp = curident;
360                         s++;
361                         while (*s)
362                         {
363                                 if (*s == '"')
364                                 {
365                                         if (s[1] != '"')
366                                                 break;
367                                         s++;
368                                 }
369                                 *cp++ = *s++;
370                         }
371                         if (*s != '"')          /* should not happen if lexer checked */
372                                 ereport(ERROR,
373                                                 (errcode(ERRCODE_SYNTAX_ERROR),
374                                                  errmsg("unterminated \" in name: %s", sstart)));
375                         s++;
376                         *cp = '\0';
377                         /* Truncate to NAMEDATALEN */
378                         truncate_identifier(curident, cp - curident, false);
379                 }
380                 else
381                 {
382                         /* Normal identifier: extends till dot or whitespace */
383                         const char *thisstart = s;
384
385                         while (*s && *s != '.' && !isspace((unsigned char) *s))
386                                 s++;
387                         /* Downcase and truncate to NAMEDATALEN */
388                         curident = downcase_truncate_identifier(thisstart, s - thisstart,
389                                                                                                         false);
390                 }
391
392                 /* Pass ident to caller */
393                 if (identctr < numidents)
394                         output[identctr++] = curident;
395                 else
396                         ereport(ERROR,
397                                         (errcode(ERRCODE_SYNTAX_ERROR),
398                                    errmsg("qualified identifier cannot be used here: %s",
399                                                   sstart)));
400
401                 /* If not done, skip whitespace, dot, whitespace */
402                 if (*s)
403                 {
404                         while (*s && isspace((unsigned char) *s))
405                                 s++;
406                         if (*s++ != '.')
407                                 elog(ERROR, "expected dot between identifiers: %s", sstart);
408                         while (*s && isspace((unsigned char) *s))
409                                 s++;
410                         if (*s == '\0')
411                                 elog(ERROR, "expected another identifier: %s", sstart);
412                 }
413         }
414
415         if (identctr != numidents)
416                 elog(ERROR, "improperly qualified identifier: %s",
417                          sstart);
418 }
419
420
421 /*
422  * Statement type as a string, for use in error messages etc.
423  */
424 const char *
425 plpgsql_stmt_typename(PLpgSQL_stmt *stmt)
426 {
427         switch (stmt->cmd_type)
428         {
429                 case PLPGSQL_STMT_BLOCK:
430                         return "block variables initialization";
431                 case PLPGSQL_STMT_ASSIGN:
432                         return "assignment";
433                 case PLPGSQL_STMT_IF:
434                         return "if";
435                 case PLPGSQL_STMT_LOOP:
436                         return "loop";
437                 case PLPGSQL_STMT_WHILE:
438                         return "while";
439                 case PLPGSQL_STMT_FORI:
440                         return "for with integer loopvar";
441                 case PLPGSQL_STMT_FORS:
442                         return "for over select rows";
443                 case PLPGSQL_STMT_SELECT:
444                         return "select into variables";
445                 case PLPGSQL_STMT_EXIT:
446                         return "exit";
447                 case PLPGSQL_STMT_RETURN:
448                         return "return";
449                 case PLPGSQL_STMT_RETURN_NEXT:
450                         return "return next";
451                 case PLPGSQL_STMT_RAISE:
452                         return "raise";
453                 case PLPGSQL_STMT_EXECSQL:
454                         return "SQL statement";
455                 case PLPGSQL_STMT_DYNEXECUTE:
456                         return "execute statement";
457                 case PLPGSQL_STMT_DYNFORS:
458                         return "for over execute statement";
459                 case PLPGSQL_STMT_GETDIAG:
460                         return "get diagnostics";
461                 case PLPGSQL_STMT_OPEN:
462                         return "open";
463                 case PLPGSQL_STMT_FETCH:
464                         return "fetch";
465                 case PLPGSQL_STMT_CLOSE:
466                         return "close";
467                 case PLPGSQL_STMT_PERFORM:
468                         return "perform";
469         }
470
471         return "unknown";
472 }
473
474
475 /**********************************************************************
476  * Debug functions for analyzing the compiled code
477  **********************************************************************/
478 static int      dump_indent;
479
480 static void dump_ind();
481 static void dump_stmt(PLpgSQL_stmt *stmt);
482 static void dump_block(PLpgSQL_stmt_block *block);
483 static void dump_assign(PLpgSQL_stmt_assign *stmt);
484 static void dump_if(PLpgSQL_stmt_if *stmt);
485 static void dump_loop(PLpgSQL_stmt_loop *stmt);
486 static void dump_while(PLpgSQL_stmt_while *stmt);
487 static void dump_fori(PLpgSQL_stmt_fori *stmt);
488 static void dump_fors(PLpgSQL_stmt_fors *stmt);
489 static void dump_select(PLpgSQL_stmt_select *stmt);
490 static void dump_exit(PLpgSQL_stmt_exit *stmt);
491 static void dump_return(PLpgSQL_stmt_return *stmt);
492 static void dump_return_next(PLpgSQL_stmt_return_next *stmt);
493 static void dump_raise(PLpgSQL_stmt_raise *stmt);
494 static void dump_execsql(PLpgSQL_stmt_execsql *stmt);
495 static void dump_dynexecute(PLpgSQL_stmt_dynexecute *stmt);
496 static void dump_dynfors(PLpgSQL_stmt_dynfors *stmt);
497 static void dump_getdiag(PLpgSQL_stmt_getdiag *stmt);
498 static void dump_open(PLpgSQL_stmt_open *stmt);
499 static void dump_fetch(PLpgSQL_stmt_fetch *stmt);
500 static void dump_close(PLpgSQL_stmt_close *stmt);
501 static void dump_perform(PLpgSQL_stmt_perform *stmt);
502 static void dump_expr(PLpgSQL_expr *expr);
503
504
505 static void
506 dump_ind()
507 {
508         int                     i;
509
510         for (i = 0; i < dump_indent; i++)
511                 printf(" ");
512 }
513
514 static void
515 dump_stmt(PLpgSQL_stmt *stmt)
516 {
517         printf("%3d:", stmt->lineno);
518         switch (stmt->cmd_type)
519         {
520                 case PLPGSQL_STMT_BLOCK:
521                         dump_block((PLpgSQL_stmt_block *) stmt);
522                         break;
523                 case PLPGSQL_STMT_ASSIGN:
524                         dump_assign((PLpgSQL_stmt_assign *) stmt);
525                         break;
526                 case PLPGSQL_STMT_IF:
527                         dump_if((PLpgSQL_stmt_if *) stmt);
528                         break;
529                 case PLPGSQL_STMT_LOOP:
530                         dump_loop((PLpgSQL_stmt_loop *) stmt);
531                         break;
532                 case PLPGSQL_STMT_WHILE:
533                         dump_while((PLpgSQL_stmt_while *) stmt);
534                         break;
535                 case PLPGSQL_STMT_FORI:
536                         dump_fori((PLpgSQL_stmt_fori *) stmt);
537                         break;
538                 case PLPGSQL_STMT_FORS:
539                         dump_fors((PLpgSQL_stmt_fors *) stmt);
540                         break;
541                 case PLPGSQL_STMT_SELECT:
542                         dump_select((PLpgSQL_stmt_select *) stmt);
543                         break;
544                 case PLPGSQL_STMT_EXIT:
545                         dump_exit((PLpgSQL_stmt_exit *) stmt);
546                         break;
547                 case PLPGSQL_STMT_RETURN:
548                         dump_return((PLpgSQL_stmt_return *) stmt);
549                         break;
550                 case PLPGSQL_STMT_RETURN_NEXT:
551                         dump_return_next((PLpgSQL_stmt_return_next *) stmt);
552                         break;
553                 case PLPGSQL_STMT_RAISE:
554                         dump_raise((PLpgSQL_stmt_raise *) stmt);
555                         break;
556                 case PLPGSQL_STMT_EXECSQL:
557                         dump_execsql((PLpgSQL_stmt_execsql *) stmt);
558                         break;
559                 case PLPGSQL_STMT_DYNEXECUTE:
560                         dump_dynexecute((PLpgSQL_stmt_dynexecute *) stmt);
561                         break;
562                 case PLPGSQL_STMT_DYNFORS:
563                         dump_dynfors((PLpgSQL_stmt_dynfors *) stmt);
564                         break;
565                 case PLPGSQL_STMT_GETDIAG:
566                         dump_getdiag((PLpgSQL_stmt_getdiag *) stmt);
567                         break;
568                 case PLPGSQL_STMT_OPEN:
569                         dump_open((PLpgSQL_stmt_open *) stmt);
570                         break;
571                 case PLPGSQL_STMT_FETCH:
572                         dump_fetch((PLpgSQL_stmt_fetch *) stmt);
573                         break;
574                 case PLPGSQL_STMT_CLOSE:
575                         dump_close((PLpgSQL_stmt_close *) stmt);
576                         break;
577                 case PLPGSQL_STMT_PERFORM:
578                         dump_perform((PLpgSQL_stmt_perform *) stmt);
579                         break;
580                 default:
581                         elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
582                         break;
583         }
584 }
585
586 static void
587 dump_stmts(PLpgSQL_stmts *stmts)
588 {
589         int                     i;
590
591         dump_indent += 2;
592         for (i = 0; i < stmts->stmts_used; i++)
593                 dump_stmt(stmts->stmts[i]);
594         dump_indent -= 2;
595 }
596
597 static void
598 dump_block(PLpgSQL_stmt_block *block)
599 {
600         int                     i;
601         char       *name;
602
603         if (block->label == NULL)
604                 name = "*unnamed*";
605         else
606                 name = block->label;
607
608         dump_ind();
609         printf("BLOCK <<%s>>\n", name);
610
611         dump_stmts(block->body);
612
613         if (block->exceptions)
614         {
615                 for (i = 0; i < block->exceptions->exceptions_used; i++)
616                 {
617                         PLpgSQL_exception *exc = block->exceptions->exceptions[i];
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         dump_ind();
657         printf("    ELSE\n");
658
659         dump_stmts(stmt->false_body);
660
661         dump_ind();
662         printf("    ENDIF\n");
663 }
664
665 static void
666 dump_loop(PLpgSQL_stmt_loop *stmt)
667 {
668         dump_ind();
669         printf("LOOP\n");
670
671         dump_stmts(stmt->body);
672
673         dump_ind();
674         printf("    ENDLOOP\n");
675 }
676
677 static void
678 dump_while(PLpgSQL_stmt_while *stmt)
679 {
680         dump_ind();
681         printf("WHILE ");
682         dump_expr(stmt->cond);
683         printf("\n");
684
685         dump_stmts(stmt->body);
686
687         dump_ind();
688         printf("    ENDWHILE\n");
689 }
690
691 static void
692 dump_fori(PLpgSQL_stmt_fori *stmt)
693 {
694         dump_ind();
695         printf("FORI %s %s\n", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL");
696
697         dump_indent += 2;
698         dump_ind();
699         printf("    lower = ");
700         dump_expr(stmt->lower);
701         printf("\n");
702         dump_ind();
703         printf("    upper = ");
704         dump_expr(stmt->upper);
705         printf("\n");
706         dump_indent -= 2;
707
708         dump_stmts(stmt->body);
709
710         dump_ind();
711         printf("    ENDFORI\n");
712 }
713
714 static void
715 dump_fors(PLpgSQL_stmt_fors *stmt)
716 {
717         dump_ind();
718         printf("FORS %s ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
719         dump_expr(stmt->query);
720         printf("\n");
721
722         dump_stmts(stmt->body);
723
724         dump_ind();
725         printf("    ENDFORS\n");
726 }
727
728 static void
729 dump_select(PLpgSQL_stmt_select *stmt)
730 {
731         dump_ind();
732         printf("SELECT ");
733         dump_expr(stmt->query);
734         printf("\n");
735
736         dump_indent += 2;
737         if (stmt->rec != NULL)
738         {
739                 dump_ind();
740                 printf("    target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
741         }
742         if (stmt->row != NULL)
743         {
744                 dump_ind();
745                 printf("    target = %d %s\n", stmt->row->rowno, stmt->row->refname);
746         }
747         dump_indent -= 2;
748
749 }
750
751 static void
752 dump_open(PLpgSQL_stmt_open *stmt)
753 {
754         dump_ind();
755         printf("OPEN curvar=%d\n", stmt->curvar);
756
757         dump_indent += 2;
758         if (stmt->argquery != NULL)
759         {
760                 dump_ind();
761                 printf("  arguments = '");
762                 dump_expr(stmt->argquery);
763                 printf("'\n");
764         }
765         if (stmt->query != NULL)
766         {
767                 dump_ind();
768                 printf("  query = '");
769                 dump_expr(stmt->query);
770                 printf("'\n");
771         }
772         if (stmt->dynquery != NULL)
773         {
774                 dump_ind();
775                 printf("  execute = '");
776                 dump_expr(stmt->dynquery);
777                 printf("'\n");
778         }
779         dump_indent -= 2;
780
781 }
782
783 static void
784 dump_fetch(PLpgSQL_stmt_fetch *stmt)
785 {
786         dump_ind();
787         printf("FETCH curvar=%d\n", stmt->curvar);
788
789         dump_indent += 2;
790         if (stmt->rec != NULL)
791         {
792                 dump_ind();
793                 printf("    target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
794         }
795         if (stmt->row != NULL)
796         {
797                 dump_ind();
798                 printf("    target = %d %s\n", stmt->row->rowno, stmt->row->refname);
799         }
800         dump_indent -= 2;
801
802 }
803
804 static void
805 dump_close(PLpgSQL_stmt_close *stmt)
806 {
807         dump_ind();
808         printf("CLOSE curvar=%d\n", stmt->curvar);
809 }
810
811 static void
812 dump_perform(PLpgSQL_stmt_perform *stmt)
813 {
814         dump_ind();
815         printf("PERFORM expr = ");
816         dump_expr(stmt->expr);
817         printf("\n");
818 }
819
820 static void
821 dump_exit(PLpgSQL_stmt_exit *stmt)
822 {
823         dump_ind();
824         printf("EXIT lbl='%s'", stmt->label);
825         if (stmt->cond != NULL)
826         {
827                 printf(" WHEN ");
828                 dump_expr(stmt->cond);
829         }
830         printf("\n");
831 }
832
833 static void
834 dump_return(PLpgSQL_stmt_return *stmt)
835 {
836         dump_ind();
837         printf("RETURN ");
838         if (stmt->retrecno >= 0)
839                 printf("record %d", stmt->retrecno);
840         else if (stmt->retrowno >= 0)
841                 printf("row %d", stmt->retrowno);
842         else if (stmt->expr == NULL)
843                 printf("NULL");
844         else
845                 dump_expr(stmt->expr);
846         printf("\n");
847 }
848
849 static void
850 dump_return_next(PLpgSQL_stmt_return_next *stmt)
851 {
852         dump_ind();
853         printf("RETURN NEXT ");
854         if (stmt->rec != NULL)
855                 printf("target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
856         else if (stmt->row != NULL)
857                 printf("target = %d %s\n", stmt->row->rowno, stmt->row->refname);
858         else if (stmt->expr != NULL)
859                 dump_expr(stmt->expr);
860         printf("\n");
861 }
862
863 static void
864 dump_raise(PLpgSQL_stmt_raise *stmt)
865 {
866         int                     i;
867
868         dump_ind();
869         printf("RAISE '%s'", stmt->message);
870         for (i = 0; i < stmt->nparams; i++)
871                 printf(" %d", stmt->params[i]);
872         printf("\n");
873 }
874
875 static void
876 dump_execsql(PLpgSQL_stmt_execsql *stmt)
877 {
878         dump_ind();
879         printf("EXECSQL ");
880         dump_expr(stmt->sqlstmt);
881         printf("\n");
882 }
883
884 static void
885 dump_dynexecute(PLpgSQL_stmt_dynexecute *stmt)
886 {
887         dump_ind();
888         printf("EXECUTE ");
889         dump_expr(stmt->query);
890         printf("\n");
891 }
892
893 static void
894 dump_dynfors(PLpgSQL_stmt_dynfors *stmt)
895 {
896         dump_ind();
897         printf("FORS %s EXECUTE ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
898         dump_expr(stmt->query);
899         printf("\n");
900
901         dump_stmts(stmt->body);
902
903         dump_ind();
904         printf("    ENDFORS\n");
905 }
906
907 static void
908 dump_getdiag(PLpgSQL_stmt_getdiag *stmt)
909 {
910         int                     i;
911
912         dump_ind();
913         printf("GET DIAGNOSTICS ");
914         for (i = 0; i < stmt->ndtitems; i++)
915         {
916                 PLpgSQL_diag_item *dtitem = &stmt->dtitems[i];
917
918                 if (i != 0)
919                         printf(", ");
920
921                 printf("{var %d} = ", dtitem->target);
922
923                 switch (dtitem->item)
924                 {
925                         case PLPGSQL_GETDIAG_ROW_COUNT:
926                                 printf("ROW_COUNT");
927                                 break;
928
929                         case PLPGSQL_GETDIAG_RESULT_OID:
930                                 printf("RESULT_OID");
931                                 break;
932
933                         default:
934                                 printf("???");
935                                 break;
936                 }
937         }
938         printf("\n");
939 }
940
941 static void
942 dump_expr(PLpgSQL_expr *expr)
943 {
944         int                     i;
945
946         printf("'%s", expr->query);
947         if (expr->nparams > 0)
948         {
949                 printf(" {");
950                 for (i = 0; i < expr->nparams; i++)
951                 {
952                         if (i > 0)
953                                 printf(", ");
954                         printf("$%d=%d", i + 1, expr->params[i]);
955                 }
956                 printf("}");
957         }
958         printf("'");
959 }
960
961 void
962 plpgsql_dumptree(PLpgSQL_function *func)
963 {
964         int                     i;
965         PLpgSQL_datum *d;
966
967         printf("\nExecution tree of successfully compiled PL/pgSQL function %s:\n",
968                    func->fn_name);
969
970         printf("\nFunctions data area:\n");
971         for (i = 0; i < func->ndatums; i++)
972         {
973                 d = func->datums[i];
974
975                 printf("    entry %d: ", i);
976                 switch (d->dtype)
977                 {
978                         case PLPGSQL_DTYPE_VAR:
979                                 {
980                                         PLpgSQL_var *var = (PLpgSQL_var *) d;
981
982                                         printf("VAR %-16s type %s (typoid %u) atttypmod %d\n",
983                                                    var->refname, var->datatype->typname,
984                                                    var->datatype->typoid,
985                                                    var->datatype->atttypmod);
986                                         if (var->isconst)
987                                                 printf("                                  CONSTANT\n");
988                                         if (var->notnull)
989                                                 printf("                                  NOT NULL\n");
990                                         if (var->default_val != NULL)
991                                         {
992                                                 printf("                                  DEFAULT ");
993                                                 dump_expr(var->default_val);
994                                                 printf("\n");
995                                         }
996                                         if (var->cursor_explicit_expr != NULL)
997                                         {
998                                                 if (var->cursor_explicit_argrow >= 0)
999                                                         printf("                                  CURSOR argument row %d\n", var->cursor_explicit_argrow);
1000
1001                                                 printf("                                  CURSOR IS ");
1002                                                 dump_expr(var->cursor_explicit_expr);
1003                                                 printf("\n");
1004                                         }
1005                                 }
1006                                 break;
1007                         case PLPGSQL_DTYPE_ROW:
1008                                 {
1009                                         PLpgSQL_row *row = (PLpgSQL_row *) d;
1010                                         int                     i;
1011
1012                                         printf("ROW %-16s fields", row->refname);
1013                                         for (i = 0; i < row->nfields; i++)
1014                                         {
1015                                                 if (row->fieldnames[i])
1016                                                         printf(" %s=var %d", row->fieldnames[i],
1017                                                                    row->varnos[i]);
1018                                         }
1019                                         printf("\n");
1020                                 }
1021                                 break;
1022                         case PLPGSQL_DTYPE_REC:
1023                                 printf("REC %s\n", ((PLpgSQL_rec *) d)->refname);
1024                                 break;
1025                         case PLPGSQL_DTYPE_RECFIELD:
1026                                 printf("RECFIELD %-16s of REC %d\n",
1027                                            ((PLpgSQL_recfield *) d)->fieldname,
1028                                            ((PLpgSQL_recfield *) d)->recparentno);
1029                                 break;
1030                         case PLPGSQL_DTYPE_ARRAYELEM:
1031                                 printf("ARRAYELEM of VAR %d subscript ",
1032                                            ((PLpgSQL_arrayelem *) d)->arrayparentno);
1033                                 dump_expr(((PLpgSQL_arrayelem *) d)->subscript);
1034                                 printf("\n");
1035                                 break;
1036                         case PLPGSQL_DTYPE_TRIGARG:
1037                                 printf("TRIGARG ");
1038                                 dump_expr(((PLpgSQL_trigarg *) d)->argnum);
1039                                 printf("\n");
1040                                 break;
1041                         default:
1042                                 printf("??? unknown data type %d\n", d->dtype);
1043                 }
1044         }
1045         printf("\nFunctions statements:\n");
1046
1047         dump_indent = 0;
1048         printf("%3d:", func->action->lineno);
1049         dump_block(func->action);
1050         printf("\nEnd of execution tree of function %s\n\n", func->fn_name);
1051         fflush(stdout);
1052 }