]> granicus.if.org Git - postgresql/blob - src/pl/plpgsql/src/pl_funcs.c
Error message editing in src/pl. The plpython module could use another
[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  *        $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.27 2003/07/25 23:37:29 tgl 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 "mb/pg_wchar.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, 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                 int                     i;
352
353                 /* Process current identifier */
354                 curident = palloc(strlen(s) + 1);               /* surely enough room */
355                 cp = curident;
356
357                 if (*s == '"')
358                 {
359                         /* Quoted identifier: copy, collapsing out doubled quotes */
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                 }
377                 else
378                 {
379                         /*
380                          * Normal identifier: downcase, stop at dot or whitespace.
381                          *
382                          * Note that downcasing is locale-sensitive, following SQL99
383                          * rules for identifiers.  We have already decided that the
384                          * item is not a PLPGSQL keyword.
385                          */
386                         while (*s && *s != '.' && !isspace((unsigned char) *s))
387                         {
388                                 if (isupper((unsigned char) *s))
389                                         *cp++ = tolower((unsigned char) *s++);
390                                 else
391                                         *cp++ = *s++;
392                         }
393                 }
394
395                 /* Truncate to NAMEDATALEN */
396                 *cp = '\0';
397                 i = cp - curident;
398
399                 if (i >= NAMEDATALEN)
400                 {
401                         int                     len;
402
403                         len = pg_mbcliplen(curident, i, NAMEDATALEN - 1);
404                         curident[len] = '\0';
405                 }
406
407                 /* Pass ident to caller */
408                 if (identctr < numidents)
409                         output[identctr++] = curident;
410                 else
411                         ereport(ERROR,
412                                         (errcode(ERRCODE_SYNTAX_ERROR),
413                                          errmsg("qualified identifier cannot be used here: %s",
414                                                         sstart)));
415
416                 /* If not done, skip whitespace, dot, whitespace */
417                 if (*s)
418                 {
419                         while (*s && isspace((unsigned char) *s))
420                                 s++;
421                         if (*s++ != '.')
422                                 elog(ERROR, "expected dot between identifiers: %s", sstart);
423                         while (*s && isspace((unsigned char) *s))
424                                 s++;
425                         if (*s == '\0')
426                                 elog(ERROR, "expected another identifier: %s", sstart);
427                 }
428         }
429
430         if (identctr != numidents)
431                 elog(ERROR, "improperly qualified identifier: %s",
432                          sstart);
433 }
434
435
436 /*
437  * Statement type as a string, for use in error messages etc.
438  */
439 const char *
440 plpgsql_stmt_typename(PLpgSQL_stmt * stmt)
441 {
442         switch (stmt->cmd_type)
443         {
444                 case PLPGSQL_STMT_BLOCK:
445                         return "block variables initialization";
446                 case PLPGSQL_STMT_ASSIGN:
447                         return "assignment";
448                 case PLPGSQL_STMT_IF:
449                         return "if";
450                 case PLPGSQL_STMT_LOOP:
451                         return "loop";
452                 case PLPGSQL_STMT_WHILE:
453                         return "while";
454                 case PLPGSQL_STMT_FORI:
455                         return "for with integer loopvar";
456                 case PLPGSQL_STMT_FORS:
457                         return "for over select rows";
458                 case PLPGSQL_STMT_SELECT:
459                         return "select into variables";
460                 case PLPGSQL_STMT_EXIT:
461                         return "exit";
462                 case PLPGSQL_STMT_RETURN:
463                         return "return";
464                 case PLPGSQL_STMT_RETURN_NEXT:
465                         return "return next";
466                 case PLPGSQL_STMT_RAISE:
467                         return "raise";
468                 case PLPGSQL_STMT_EXECSQL:
469                         return "SQL statement";
470                 case PLPGSQL_STMT_DYNEXECUTE:
471                         return "execute statement";
472                 case PLPGSQL_STMT_DYNFORS:
473                         return "for over execute statement";
474                 case PLPGSQL_STMT_GETDIAG:
475                         return "get diagnostics";
476                 case PLPGSQL_STMT_OPEN:
477                         return "open";
478                 case PLPGSQL_STMT_FETCH:
479                         return "fetch";
480                 case PLPGSQL_STMT_CLOSE:
481                         return "close";
482                 case PLPGSQL_STMT_PERFORM:
483                         return "perform";
484         }
485
486         return "unknown";
487 }
488
489
490 /**********************************************************************
491  * Debug functions for analyzing the compiled code
492  **********************************************************************/
493 static int      dump_indent;
494
495 static void dump_ind();
496 static void dump_stmt(PLpgSQL_stmt * stmt);
497 static void dump_block(PLpgSQL_stmt_block * block);
498 static void dump_assign(PLpgSQL_stmt_assign * stmt);
499 static void dump_if(PLpgSQL_stmt_if * stmt);
500 static void dump_loop(PLpgSQL_stmt_loop * stmt);
501 static void dump_while(PLpgSQL_stmt_while * stmt);
502 static void dump_fori(PLpgSQL_stmt_fori * stmt);
503 static void dump_fors(PLpgSQL_stmt_fors * stmt);
504 static void dump_select(PLpgSQL_stmt_select * stmt);
505 static void dump_exit(PLpgSQL_stmt_exit * stmt);
506 static void dump_return(PLpgSQL_stmt_return * stmt);
507 static void dump_return_next(PLpgSQL_stmt_return_next * stmt);
508 static void dump_raise(PLpgSQL_stmt_raise * stmt);
509 static void dump_execsql(PLpgSQL_stmt_execsql * stmt);
510 static void dump_dynexecute(PLpgSQL_stmt_dynexecute * stmt);
511 static void dump_dynfors(PLpgSQL_stmt_dynfors * stmt);
512 static void dump_getdiag(PLpgSQL_stmt_getdiag * stmt);
513 static void dump_open(PLpgSQL_stmt_open * stmt);
514 static void dump_fetch(PLpgSQL_stmt_fetch * stmt);
515 static void dump_close(PLpgSQL_stmt_close * stmt);
516 static void dump_perform(PLpgSQL_stmt_perform * stmt);
517 static void dump_expr(PLpgSQL_expr * expr);
518
519
520 static void
521 dump_ind()
522 {
523         int                     i;
524
525         for (i = 0; i < dump_indent; i++)
526                 printf(" ");
527 }
528
529 static void
530 dump_stmt(PLpgSQL_stmt * stmt)
531 {
532         printf("%3d:", stmt->lineno);
533         switch (stmt->cmd_type)
534         {
535                 case PLPGSQL_STMT_BLOCK:
536                         dump_block((PLpgSQL_stmt_block *) stmt);
537                         break;
538                 case PLPGSQL_STMT_ASSIGN:
539                         dump_assign((PLpgSQL_stmt_assign *) stmt);
540                         break;
541                 case PLPGSQL_STMT_IF:
542                         dump_if((PLpgSQL_stmt_if *) stmt);
543                         break;
544                 case PLPGSQL_STMT_LOOP:
545                         dump_loop((PLpgSQL_stmt_loop *) stmt);
546                         break;
547                 case PLPGSQL_STMT_WHILE:
548                         dump_while((PLpgSQL_stmt_while *) stmt);
549                         break;
550                 case PLPGSQL_STMT_FORI:
551                         dump_fori((PLpgSQL_stmt_fori *) stmt);
552                         break;
553                 case PLPGSQL_STMT_FORS:
554                         dump_fors((PLpgSQL_stmt_fors *) stmt);
555                         break;
556                 case PLPGSQL_STMT_SELECT:
557                         dump_select((PLpgSQL_stmt_select *) stmt);
558                         break;
559                 case PLPGSQL_STMT_EXIT:
560                         dump_exit((PLpgSQL_stmt_exit *) stmt);
561                         break;
562                 case PLPGSQL_STMT_RETURN:
563                         dump_return((PLpgSQL_stmt_return *) stmt);
564                         break;
565                 case PLPGSQL_STMT_RETURN_NEXT:
566                         dump_return_next((PLpgSQL_stmt_return_next *) stmt);
567                         break;
568                 case PLPGSQL_STMT_RAISE:
569                         dump_raise((PLpgSQL_stmt_raise *) stmt);
570                         break;
571                 case PLPGSQL_STMT_EXECSQL:
572                         dump_execsql((PLpgSQL_stmt_execsql *) stmt);
573                         break;
574                 case PLPGSQL_STMT_DYNEXECUTE:
575                         dump_dynexecute((PLpgSQL_stmt_dynexecute *) stmt);
576                         break;
577                 case PLPGSQL_STMT_DYNFORS:
578                         dump_dynfors((PLpgSQL_stmt_dynfors *) stmt);
579                         break;
580                 case PLPGSQL_STMT_GETDIAG:
581                         dump_getdiag((PLpgSQL_stmt_getdiag *) stmt);
582                         break;
583                 case PLPGSQL_STMT_OPEN:
584                         dump_open((PLpgSQL_stmt_open *) stmt);
585                         break;
586                 case PLPGSQL_STMT_FETCH:
587                         dump_fetch((PLpgSQL_stmt_fetch *) stmt);
588                         break;
589                 case PLPGSQL_STMT_CLOSE:
590                         dump_close((PLpgSQL_stmt_close *) stmt);
591                         break;
592                 case PLPGSQL_STMT_PERFORM:
593                         dump_perform((PLpgSQL_stmt_perform *) stmt);
594                         break;
595                 default:
596                         elog(ERROR, "unknown cmd_type: %d", stmt->cmd_type);
597                         break;
598         }
599 }
600
601 static void
602 dump_block(PLpgSQL_stmt_block * block)
603 {
604         int                     i;
605         char       *name;
606
607         if (block->label == NULL)
608                 name = "*unnamed*";
609         else
610                 name = block->label;
611
612         dump_ind();
613         printf("BLOCK <<%s>>\n", name);
614
615         dump_indent += 2;
616         for (i = 0; i < block->body->stmts_used; i++)
617                 dump_stmt((PLpgSQL_stmt *) (block->body->stmts[i]));
618         dump_indent -= 2;
619
620         dump_ind();
621         printf("    END -- %s\n", name);
622 }
623
624 static void
625 dump_assign(PLpgSQL_stmt_assign * stmt)
626 {
627         dump_ind();
628         printf("ASSIGN var %d := ", stmt->varno);
629         dump_expr(stmt->expr);
630         printf("\n");
631 }
632
633 static void
634 dump_if(PLpgSQL_stmt_if * stmt)
635 {
636         int                     i;
637
638         dump_ind();
639         printf("IF ");
640         dump_expr(stmt->cond);
641         printf(" THEN\n");
642
643         dump_indent += 2;
644         for (i = 0; i < stmt->true_body->stmts_used; i++)
645                 dump_stmt((PLpgSQL_stmt *) (stmt->true_body->stmts[i]));
646         dump_indent -= 2;
647
648         dump_ind();
649         printf("    ELSE\n");
650
651         dump_indent += 2;
652         for (i = 0; i < stmt->false_body->stmts_used; i++)
653                 dump_stmt((PLpgSQL_stmt *) (stmt->false_body->stmts[i]));
654         dump_indent -= 2;
655
656         dump_ind();
657         printf("    ENDIF\n");
658 }
659
660 static void
661 dump_loop(PLpgSQL_stmt_loop * stmt)
662 {
663         int                     i;
664
665         dump_ind();
666         printf("LOOP\n");
667
668         dump_indent += 2;
669         for (i = 0; i < stmt->body->stmts_used; i++)
670                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
671         dump_indent -= 2;
672
673         dump_ind();
674         printf("    ENDLOOP\n");
675 }
676
677 static void
678 dump_while(PLpgSQL_stmt_while * stmt)
679 {
680         int                     i;
681
682         dump_ind();
683         printf("WHILE ");
684         dump_expr(stmt->cond);
685         printf("\n");
686
687         dump_indent += 2;
688         for (i = 0; i < stmt->body->stmts_used; i++)
689                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
690         dump_indent -= 2;
691
692         dump_ind();
693         printf("    ENDWHILE\n");
694 }
695
696 static void
697 dump_fori(PLpgSQL_stmt_fori * stmt)
698 {
699         int                     i;
700
701         dump_ind();
702         printf("FORI %s %s\n", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL");
703
704         dump_indent += 2;
705         dump_ind();
706         printf("    lower = ");
707         dump_expr(stmt->lower);
708         printf("\n");
709         dump_ind();
710         printf("    upper = ");
711         dump_expr(stmt->upper);
712         printf("\n");
713
714         for (i = 0; i < stmt->body->stmts_used; i++)
715                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
716         dump_indent -= 2;
717
718         dump_ind();
719         printf("    ENDFORI\n");
720 }
721
722 static void
723 dump_fors(PLpgSQL_stmt_fors * stmt)
724 {
725         int                     i;
726
727         dump_ind();
728         printf("FORS %s ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
729         dump_expr(stmt->query);
730         printf("\n");
731
732         dump_indent += 2;
733         for (i = 0; i < stmt->body->stmts_used; i++)
734                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
735         dump_indent -= 2;
736
737         dump_ind();
738         printf("    ENDFORS\n");
739 }
740
741 static void
742 dump_select(PLpgSQL_stmt_select * stmt)
743 {
744         dump_ind();
745         printf("SELECT ");
746         dump_expr(stmt->query);
747         printf("\n");
748
749         dump_indent += 2;
750         if (stmt->rec != NULL)
751         {
752                 dump_ind();
753                 printf("    target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
754         }
755         if (stmt->row != NULL)
756         {
757                 dump_ind();
758                 printf("    target = %d %s\n", stmt->row->rowno, stmt->row->refname);
759         }
760         dump_indent -= 2;
761
762 }
763
764 static void
765 dump_open(PLpgSQL_stmt_open * stmt)
766 {
767         dump_ind();
768         printf("OPEN curvar=%d\n", stmt->curvar);
769
770         dump_indent += 2;
771         if (stmt->argquery != NULL)
772         {
773                 dump_ind();
774                 printf("  arguments = '");
775                 dump_expr(stmt->argquery);
776                 printf("'\n");
777         }
778         if (stmt->query != NULL)
779         {
780                 dump_ind();
781                 printf("  query = '");
782                 dump_expr(stmt->query);
783                 printf("'\n");
784         }
785         if (stmt->dynquery != NULL)
786         {
787                 dump_ind();
788                 printf("  execute = '");
789                 dump_expr(stmt->dynquery);
790                 printf("'\n");
791         }
792         dump_indent -= 2;
793
794 }
795
796 static void
797 dump_fetch(PLpgSQL_stmt_fetch * stmt)
798 {
799         dump_ind();
800         printf("FETCH curvar=%d\n", stmt->curvar);
801
802         dump_indent += 2;
803         if (stmt->rec != NULL)
804         {
805                 dump_ind();
806                 printf("    target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
807         }
808         if (stmt->row != NULL)
809         {
810                 dump_ind();
811                 printf("    target = %d %s\n", stmt->row->rowno, stmt->row->refname);
812         }
813         dump_indent -= 2;
814
815 }
816
817 static void
818 dump_close(PLpgSQL_stmt_close * stmt)
819 {
820         dump_ind();
821         printf("CLOSE curvar=%d\n", stmt->curvar);
822 }
823
824 static void
825 dump_perform(PLpgSQL_stmt_perform * stmt)
826 {
827         dump_ind();
828         printf("PERFORM expr = ");
829         dump_expr(stmt->expr);
830         printf("\n");
831 }
832
833 static void
834 dump_exit(PLpgSQL_stmt_exit * stmt)
835 {
836         dump_ind();
837         printf("EXIT lbl='%s'", stmt->label);
838         if (stmt->cond != NULL)
839         {
840                 printf(" WHEN ");
841                 dump_expr(stmt->cond);
842         }
843         printf("\n");
844 }
845
846 static void
847 dump_return(PLpgSQL_stmt_return * stmt)
848 {
849         dump_ind();
850         printf("RETURN ");
851         if (stmt->retrecno > 0)
852                 printf("record %d", stmt->retrecno);
853         else
854         {
855                 if (stmt->expr == NULL)
856                         printf("NULL");
857                 else
858                         dump_expr(stmt->expr);
859         }
860         printf("\n");
861 }
862
863 static void
864 dump_return_next(PLpgSQL_stmt_return_next * stmt)
865 {
866         dump_ind();
867         printf("RETURN NEXT ");
868         if (stmt->rec != NULL)
869                 printf("target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
870         else if (stmt->row != NULL)
871                 printf("target = %d %s\n", stmt->row->rowno, stmt->row->refname);
872         else if (stmt->expr != NULL)
873                 dump_expr(stmt->expr);
874         printf("\n");
875 }
876
877 static void
878 dump_raise(PLpgSQL_stmt_raise * stmt)
879 {
880         int                     i;
881
882         dump_ind();
883         printf("RAISE '%s'", stmt->message);
884         for (i = 0; i < stmt->nparams; i++)
885                 printf(" %d", stmt->params[i]);
886         printf("\n");
887 }
888
889 static void
890 dump_execsql(PLpgSQL_stmt_execsql * stmt)
891 {
892         dump_ind();
893         printf("EXECSQL ");
894         dump_expr(stmt->sqlstmt);
895         printf("\n");
896 }
897
898 static void
899 dump_dynexecute(PLpgSQL_stmt_dynexecute * stmt)
900 {
901         dump_ind();
902         printf("EXECUTE ");
903         dump_expr(stmt->query);
904         printf("\n");
905 }
906
907 static void
908 dump_dynfors(PLpgSQL_stmt_dynfors * stmt)
909 {
910         int                     i;
911
912         dump_ind();
913         printf("FORS %s EXECUTE ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
914         dump_expr(stmt->query);
915         printf("\n");
916
917         dump_indent += 2;
918         for (i = 0; i < stmt->body->stmts_used; i++)
919                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
920         dump_indent -= 2;
921
922         dump_ind();
923         printf("    ENDFORS\n");
924 }
925
926 static void
927 dump_getdiag(PLpgSQL_stmt_getdiag * stmt)
928 {
929         int                     i;
930
931         dump_ind();
932         printf("GET DIAGNOSTICS ");
933         for (i = 0; i < stmt->ndtitems; i++)
934         {
935                 PLpgSQL_diag_item *dtitem = &stmt->dtitems[i];
936
937                 if (i != 0)
938                         printf(", ");
939
940                 printf("{var %d} = ", dtitem->target);
941
942                 switch (dtitem->item)
943                 {
944                         case PLPGSQL_GETDIAG_ROW_COUNT:
945                                 printf("ROW_COUNT");
946                                 break;
947
948                         case PLPGSQL_GETDIAG_RESULT_OID:
949                                 printf("RESULT_OID");
950                                 break;
951
952                         default:
953                                 printf("???");
954                                 break;
955                 }
956         }
957         printf("\n");
958 }
959
960 static void
961 dump_expr(PLpgSQL_expr * expr)
962 {
963         int                     i;
964
965         printf("'%s", expr->query);
966         if (expr->nparams > 0)
967         {
968                 printf(" {");
969                 for (i = 0; i < expr->nparams; i++)
970                 {
971                         if (i > 0)
972                                 printf(", ");
973                         printf("$%d=%d", i + 1, expr->params[i]);
974                 }
975                 printf("}");
976         }
977         printf("'");
978 }
979
980 void
981 plpgsql_dumptree(PLpgSQL_function * func)
982 {
983         int                     i;
984         PLpgSQL_datum *d;
985
986         printf("\nExecution tree of successfully compiled PL/pgSQL function %s:\n",
987                    func->fn_name);
988
989         printf("\nFunctions data area:\n");
990         for (i = 0; i < func->ndatums; i++)
991         {
992                 d = func->datums[i];
993
994                 printf("    entry %d: ", i);
995                 switch (d->dtype)
996                 {
997                         case PLPGSQL_DTYPE_VAR:
998                                 {
999                                         PLpgSQL_var *var = (PLpgSQL_var *) d;
1000
1001                                         printf("VAR %-16s type %s (typoid %u) atttypmod %d\n",
1002                                                    var->refname, var->datatype->typname,
1003                                                    var->datatype->typoid,
1004                                                    var->datatype->atttypmod);
1005                                         if (var->isconst)
1006                                                 printf("                                  CONSTANT\n");
1007                                         if (var->notnull)
1008                                                 printf("                                  NOT NULL\n");
1009                                         if (var->default_val != NULL)
1010                                         {
1011                                                 printf("                                  DEFAULT ");
1012                                                 dump_expr(var->default_val);
1013                                                 printf("\n");
1014                                         }
1015                                         if (var->cursor_explicit_expr != NULL)
1016                                         {
1017                                                 if (var->cursor_explicit_argrow >= 0)
1018                                                         printf("                                  CURSOR argument row %d\n", var->cursor_explicit_argrow);
1019
1020                                                 printf("                                  CURSOR IS ");
1021                                                 dump_expr(var->cursor_explicit_expr);
1022                                                 printf("\n");
1023                                         }
1024                                 }
1025                                 break;
1026                         case PLPGSQL_DTYPE_ROW:
1027                                 {
1028                                         PLpgSQL_row *row = (PLpgSQL_row *) d;
1029                                         int                     i;
1030
1031                                         printf("ROW %-16s fields", row->refname);
1032                                         for (i = 0; i < row->nfields; i++)
1033                                         {
1034                                                 printf(" %s=var %d", row->fieldnames[i],
1035                                                            row->varnos[i]);
1036                                         }
1037                                         printf("\n");
1038                                 }
1039                                 break;
1040                         case PLPGSQL_DTYPE_REC:
1041                                 printf("REC %s\n", ((PLpgSQL_rec *) d)->refname);
1042                                 break;
1043                         case PLPGSQL_DTYPE_RECFIELD:
1044                                 printf("RECFIELD %-16s of REC %d\n",
1045                                            ((PLpgSQL_recfield *) d)->fieldname,
1046                                            ((PLpgSQL_recfield *) d)->recparentno);
1047                                 break;
1048                         case PLPGSQL_DTYPE_ARRAYELEM:
1049                                 printf("ARRAYELEM of VAR %d subscript ", 
1050                                            ((PLpgSQL_arrayelem *) d)->arrayparentno);
1051                                 dump_expr(((PLpgSQL_arrayelem *) d)->subscript);
1052                                 printf("\n");
1053                                 break;
1054                         case PLPGSQL_DTYPE_TRIGARG:
1055                                 printf("TRIGARG ");
1056                                 dump_expr(((PLpgSQL_trigarg *) d)->argnum);
1057                                 printf("\n");
1058                                 break;
1059                         default:
1060                                 printf("??? unknown data type %d\n", d->dtype);
1061                 }
1062         }
1063         printf("\nFunctions statements:\n");
1064
1065         dump_indent = 0;
1066         printf("%3d:", func->action->lineno);
1067         dump_block(func->action);
1068         printf("\nEnd of execution tree of function %s\n\n", func->fn_name);
1069 }