]> granicus.if.org Git - postgresql/blob - src/pl/plpgsql/src/pl_funcs.c
Back out SET AUTHORIZATION patch until security is resolved.
[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.15 2001/07/12 17:42:08 momjian 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 <stdio.h>
39 #include <stdlib.h>
40 #include <stdarg.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <string.h>
44 #include <ctype.h>
45
46 #include "plpgsql.h"
47 #include "pl.tab.h"
48
49
50 /* ----------
51  * Local variables for the namestack handling
52  * ----------
53  */
54 static PLpgSQL_ns *ns_current = NULL;
55 static bool ns_localmode = false;
56
57
58 /* ----------
59  * plpgsql_dstring_init                 Dynamic string initialization
60  * ----------
61  */
62 void
63 plpgsql_dstring_init(PLpgSQL_dstring * ds)
64 {
65         ds->value = palloc(ds->alloc = 512);
66         ds->used = 0;
67 }
68
69
70 /* ----------
71  * plpgsql_dstring_free                 Dynamic string destruction
72  * ----------
73  */
74 void
75 plpgsql_dstring_free(PLpgSQL_dstring * ds)
76 {
77         pfree(ds->value);
78 }
79
80
81 /* ----------
82  * plpgsql_dstring_append               Dynamic string extending
83  * ----------
84  */
85 void
86 plpgsql_dstring_append(PLpgSQL_dstring * ds, char *str)
87 {
88         int                     len = strlen(str);
89
90         if (ds->used + len + 1 > ds->alloc)
91         {
92                 ds->alloc *= 2;
93                 ds->value = repalloc(ds->value, ds->alloc);
94         }
95
96         strcpy(&(ds->value[ds->used]), str);
97         ds->used += len;
98 }
99
100
101 /* ----------
102  * plpgsql_dstring_get                  Dynamic string get value
103  * ----------
104  */
105 char *
106 plpgsql_dstring_get(PLpgSQL_dstring * ds)
107 {
108         return ds->value;
109 }
110
111
112 /* ----------
113  * plpgsql_ns_init                      Initialize the namestack
114  * ----------
115  */
116 void
117 plpgsql_ns_init(void)
118 {
119         ns_current = NULL;
120         ns_localmode = false;
121 }
122
123
124 /* ----------
125  * plpgsql_ns_setlocal                  Tell plpgsql_ns_lookup to or to
126  *                                      not look into the current level
127  *                                      only.
128  * ----------
129  */
130 bool
131 plpgsql_ns_setlocal(bool flag)
132 {
133         bool            oldstate;
134
135         oldstate = ns_localmode;
136         ns_localmode = flag;
137         return oldstate;
138 }
139
140
141 /* ----------
142  * plpgsql_ns_push                      Enter a new namestack level
143  * ----------
144  */
145 void
146 plpgsql_ns_push(char *label)
147 {
148         PLpgSQL_ns *new;
149
150         new = palloc(sizeof(PLpgSQL_ns));
151         memset(new, 0, sizeof(PLpgSQL_ns));
152         new->upper = ns_current;
153         ns_current = new;
154
155         plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, 0, label);
156 }
157
158
159 /* ----------
160  * plpgsql_ns_pop                       Return to the previous level
161  * ----------
162  */
163 void
164 plpgsql_ns_pop()
165 {
166         int                     i;
167         PLpgSQL_ns *old;
168
169         old = ns_current;
170         ns_current = old->upper;
171
172         for (i = 0; i < old->items_used; i++)
173                 pfree(old->items[i]);
174         pfree(old->items);
175         pfree(old);
176 }
177
178
179 /* ----------
180  * plpgsql_ns_additem                   Add an item to the current
181  *                                      namestack level
182  * ----------
183  */
184 void
185 plpgsql_ns_additem(int itemtype, int itemno, char *name)
186 {
187         PLpgSQL_ns *ns = ns_current;
188         PLpgSQL_nsitem *nse;
189
190         if (name == NULL)
191                 name = "";
192         name = plpgsql_tolower(name);
193
194         if (ns->items_used == ns->items_alloc)
195         {
196                 if (ns->items_alloc == 0)
197                 {
198                         ns->items_alloc = 32;
199                         ns->items = palloc(sizeof(PLpgSQL_nsitem *) * ns->items_alloc);
200                 }
201                 else
202                 {
203                         ns->items_alloc *= 2;
204                         ns->items = repalloc(ns->items,
205                                                          sizeof(PLpgSQL_nsitem *) * ns->items_alloc);
206                 }
207         }
208
209         nse = palloc(sizeof(PLpgSQL_nsitem) + strlen(name));
210         nse->itemtype = itemtype;
211         nse->itemno = itemno;
212         strcpy(nse->name, name);
213         ns->items[ns->items_used++] = nse;
214 }
215
216
217 /* ----------
218  * plpgsql_ns_lookup                    Lookup for a word in the namestack
219  * ----------
220  */
221 PLpgSQL_nsitem *
222 plpgsql_ns_lookup(char *name, char *label)
223 {
224         PLpgSQL_ns *ns;
225         int                     i;
226
227         /*
228          * If a label is specified, lookup only in that
229          */
230         if (label != NULL)
231         {
232                 for (ns = ns_current; ns != NULL; ns = ns->upper)
233                 {
234                         if (!strcmp(ns->items[0]->name, label))
235                         {
236                                 for (i = 1; i < ns->items_used; i++)
237                                 {
238                                         if (!strcmp(ns->items[i]->name, name))
239                                                 return ns->items[i];
240                                 }
241                                 return NULL;    /* name not found in specified label */
242                         }
243                 }
244                 return NULL;                    /* label not found */
245         }
246
247         /*
248          * No label given, lookup for visible labels ignoring localmode
249          */
250         for (ns = ns_current; ns != NULL; ns = ns->upper)
251         {
252                 if (!strcmp(ns->items[0]->name, name))
253                         return ns->items[0];
254         }
255
256         /*
257          * Finally lookup name in the namestack
258          */
259         for (ns = ns_current; ns != NULL; ns = ns->upper)
260         {
261                 for (i = 1; i < ns->items_used; i++)
262                 {
263                         if (!strcmp(ns->items[i]->name, name))
264                                 return ns->items[i];
265                 }
266                 if (ns_localmode)
267                 {
268                         return NULL;            /* name not found in current namespace */
269                 }
270         }
271
272         return NULL;
273 }
274
275
276 /* ----------
277  * plpgsql_ns_rename                    Rename a namespace entry
278  * ----------
279  */
280 void
281 plpgsql_ns_rename(char *oldname, char *newname)
282 {
283         PLpgSQL_ns *ns;
284         PLpgSQL_nsitem *newitem;
285         int                     i;
286
287         /*
288          * Lookup in the current namespace only
289          */
290
291         /*
292          * Lookup name in the namestack
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         elog(ERROR, "there is no variable '%s' in the current block", oldname);
316 }
317
318
319 /* ----------
320  * plpgsql_tolower                      Translate a string to lower case
321  *                                      but honor "" escaping.
322  * ----------
323  */
324 char *
325 plpgsql_tolower(char *s)
326 {
327         char       *ret;
328         char       *cp;
329
330         ret = palloc(strlen(s) + 1);
331         cp = ret;
332
333         while (*s)
334         {
335                 if (*s == '"')
336                 {
337                         s++;
338                         while (*s)
339                         {
340                                 if (*s == '"')
341                                         break;
342                                 *cp++ = *s++;
343                         }
344                         if (*s != '"')
345                         {
346                                 plpgsql_comperrinfo();
347                                 elog(ERROR, "unterminated \"");
348                         }
349                         s++;
350                 }
351                 else
352                 {
353                         if (isupper((unsigned char) *s))
354                                 *cp++ = tolower((unsigned char) *s++);
355                         else
356                                 *cp++ = *s++;
357                 }
358         }
359         *cp = '\0';
360
361         return ret;
362 }
363
364
365
366
367
368 /**********************************************************************
369  * Debug functions for analyzing the compiled code
370  **********************************************************************/
371 static int      dump_indent;
372
373 static void dump_ind();
374 static void dump_stmt(PLpgSQL_stmt * stmt);
375 static void dump_block(PLpgSQL_stmt_block * block);
376 static void dump_assign(PLpgSQL_stmt_assign * stmt);
377 static void dump_if(PLpgSQL_stmt_if * stmt);
378 static void dump_loop(PLpgSQL_stmt_loop * stmt);
379 static void dump_while(PLpgSQL_stmt_while * stmt);
380 static void dump_fori(PLpgSQL_stmt_fori * stmt);
381 static void dump_fors(PLpgSQL_stmt_fors * stmt);
382 static void dump_select(PLpgSQL_stmt_select * stmt);
383 static void dump_exit(PLpgSQL_stmt_exit * stmt);
384 static void dump_return(PLpgSQL_stmt_return * stmt);
385 static void dump_raise(PLpgSQL_stmt_raise * stmt);
386 static void dump_execsql(PLpgSQL_stmt_execsql * stmt);
387 static void dump_dynexecute(PLpgSQL_stmt_dynexecute * stmt);
388 static void dump_dynfors(PLpgSQL_stmt_dynfors * stmt);
389 static void dump_getdiag(PLpgSQL_stmt_getdiag * stmt);
390 static void dump_open(PLpgSQL_stmt_open * stmt);
391 static void dump_fetch(PLpgSQL_stmt_fetch * stmt);
392 static void dump_close(PLpgSQL_stmt_close * stmt);
393 static void dump_expr(PLpgSQL_expr * expr);
394
395
396 static void
397 dump_ind()
398 {
399         int                     i;
400
401         for (i = 0; i < dump_indent; i++)
402                 printf(" ");
403 }
404
405 static void
406 dump_stmt(PLpgSQL_stmt * stmt)
407 {
408         printf("%3d:", stmt->lineno);
409         switch (stmt->cmd_type)
410         {
411                 case PLPGSQL_STMT_BLOCK:
412                         dump_block((PLpgSQL_stmt_block *) stmt);
413                         break;
414                 case PLPGSQL_STMT_ASSIGN:
415                         dump_assign((PLpgSQL_stmt_assign *) stmt);
416                         break;
417                 case PLPGSQL_STMT_IF:
418                         dump_if((PLpgSQL_stmt_if *) stmt);
419                         break;
420                 case PLPGSQL_STMT_LOOP:
421                         dump_loop((PLpgSQL_stmt_loop *) stmt);
422                         break;
423                 case PLPGSQL_STMT_WHILE:
424                         dump_while((PLpgSQL_stmt_while *) stmt);
425                         break;
426                 case PLPGSQL_STMT_FORI:
427                         dump_fori((PLpgSQL_stmt_fori *) stmt);
428                         break;
429                 case PLPGSQL_STMT_FORS:
430                         dump_fors((PLpgSQL_stmt_fors *) stmt);
431                         break;
432                 case PLPGSQL_STMT_SELECT:
433                         dump_select((PLpgSQL_stmt_select *) stmt);
434                         break;
435                 case PLPGSQL_STMT_EXIT:
436                         dump_exit((PLpgSQL_stmt_exit *) stmt);
437                         break;
438                 case PLPGSQL_STMT_RETURN:
439                         dump_return((PLpgSQL_stmt_return *) stmt);
440                         break;
441                 case PLPGSQL_STMT_RAISE:
442                         dump_raise((PLpgSQL_stmt_raise *) stmt);
443                         break;
444                 case PLPGSQL_STMT_EXECSQL:
445                         dump_execsql((PLpgSQL_stmt_execsql *) stmt);
446                         break;
447                 case PLPGSQL_STMT_DYNEXECUTE:
448                         dump_dynexecute((PLpgSQL_stmt_dynexecute *) stmt);
449                         break;
450                 case PLPGSQL_STMT_DYNFORS:
451                         dump_dynfors((PLpgSQL_stmt_dynfors *) stmt);
452                         break;
453                 case PLPGSQL_STMT_GETDIAG:
454                         dump_getdiag((PLpgSQL_stmt_getdiag *) stmt);
455                         break;
456                 case PLPGSQL_STMT_OPEN:
457                         dump_open((PLpgSQL_stmt_open *) stmt);
458                         break;
459                 case PLPGSQL_STMT_FETCH:
460                         dump_fetch((PLpgSQL_stmt_fetch *) stmt);
461                         break;
462                 case PLPGSQL_STMT_CLOSE:
463                         dump_close((PLpgSQL_stmt_close *) stmt);
464                         break;
465                 default:
466                         elog(ERROR, "plpgsql_dump: unknown cmd_type %d\n", stmt->cmd_type);
467                         break;
468         }
469 }
470
471 static void
472 dump_block(PLpgSQL_stmt_block * block)
473 {
474         int                     i;
475         char       *name;
476
477         if (block->label == NULL)
478                 name = "*unnamed*";
479         else
480                 name = block->label;
481
482         dump_ind();
483         printf("BLOCK <<%s>>\n", name);
484
485         dump_indent += 2;
486         for (i = 0; i < block->body->stmts_used; i++)
487                 dump_stmt((PLpgSQL_stmt *) (block->body->stmts[i]));
488         dump_indent -= 2;
489
490         dump_ind();
491         printf("    END -- %s\n", name);
492 }
493
494 static void
495 dump_assign(PLpgSQL_stmt_assign * stmt)
496 {
497         dump_ind();
498         printf("ASSIGN var %d := ", stmt->varno);
499         dump_expr(stmt->expr);
500         printf("\n");
501 }
502
503 static void
504 dump_if(PLpgSQL_stmt_if * stmt)
505 {
506         int                     i;
507
508         dump_ind();
509         printf("IF ");
510         dump_expr(stmt->cond);
511         printf(" THEN\n");
512
513         dump_indent += 2;
514         for (i = 0; i < stmt->true_body->stmts_used; i++)
515                 dump_stmt((PLpgSQL_stmt *) (stmt->true_body->stmts[i]));
516         dump_indent -= 2;
517
518         dump_ind();
519         printf("    ELSE\n");
520
521         dump_indent += 2;
522         for (i = 0; i < stmt->false_body->stmts_used; i++)
523                 dump_stmt((PLpgSQL_stmt *) (stmt->false_body->stmts[i]));
524         dump_indent -= 2;
525
526         dump_ind();
527         printf("    ENDIF\n");
528 }
529
530 static void
531 dump_loop(PLpgSQL_stmt_loop * stmt)
532 {
533         int                     i;
534
535         dump_ind();
536         printf("LOOP\n");
537
538         dump_indent += 2;
539         for (i = 0; i < stmt->body->stmts_used; i++)
540                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
541         dump_indent -= 2;
542
543         dump_ind();
544         printf("    ENDLOOP\n");
545 }
546
547 static void
548 dump_while(PLpgSQL_stmt_while * stmt)
549 {
550         int                     i;
551
552         dump_ind();
553         printf("WHILE ");
554         dump_expr(stmt->cond);
555         printf("\n");
556
557         dump_indent += 2;
558         for (i = 0; i < stmt->body->stmts_used; i++)
559                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
560         dump_indent -= 2;
561
562         dump_ind();
563         printf("    ENDWHILE\n");
564 }
565
566 static void
567 dump_fori(PLpgSQL_stmt_fori * stmt)
568 {
569         int                     i;
570
571         dump_ind();
572         printf("FORI %s %s\n", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL");
573
574         dump_indent += 2;
575         dump_ind();
576         printf("    lower = ");
577         dump_expr(stmt->lower);
578         printf("\n");
579         dump_ind();
580         printf("    upper = ");
581         dump_expr(stmt->upper);
582         printf("\n");
583
584         for (i = 0; i < stmt->body->stmts_used; i++)
585                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
586         dump_indent -= 2;
587
588         dump_ind();
589         printf("    ENDFORI\n");
590 }
591
592 static void
593 dump_fors(PLpgSQL_stmt_fors * stmt)
594 {
595         int                     i;
596
597         dump_ind();
598         printf("FORS %s ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
599         dump_expr(stmt->query);
600         printf("\n");
601
602         dump_indent += 2;
603         for (i = 0; i < stmt->body->stmts_used; i++)
604                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
605         dump_indent -= 2;
606
607         dump_ind();
608         printf("    ENDFORS\n");
609 }
610
611 static void
612 dump_select(PLpgSQL_stmt_select * stmt)
613 {
614         dump_ind();
615         printf("SELECT ");
616         dump_expr(stmt->query);
617         printf("\n");
618
619         dump_indent += 2;
620         if (stmt->rec != NULL)
621         {
622                 dump_ind();
623                 printf("    target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
624         }
625         if (stmt->row != NULL)
626         {
627                 dump_ind();
628                 printf("    target = %d %s\n", stmt->row->rowno, stmt->row->refname);
629         }
630         dump_indent -= 2;
631
632 }
633
634 static void
635 dump_open(PLpgSQL_stmt_open * stmt)
636 {
637         dump_ind();
638         printf("OPEN curvar=%d\n", stmt->curvar);
639
640         dump_indent += 2;
641         if (stmt->argquery != NULL)
642         {
643                 dump_ind();
644                 printf("  arguments = '");
645                 dump_expr(stmt->argquery);
646                 printf("'\n");
647         }
648         if (stmt->query != NULL)
649         {
650                 dump_ind();
651                 printf("  query = '");
652                 dump_expr(stmt->query);
653                 printf("'\n");
654         }
655         if (stmt->dynquery != NULL)
656         {
657                 dump_ind();
658                 printf("  execute = '");
659                 dump_expr(stmt->dynquery);
660                 printf("'\n");
661         }
662         dump_indent -= 2;
663
664 }
665
666 static void
667 dump_fetch(PLpgSQL_stmt_fetch * stmt)
668 {
669         dump_ind();
670         printf("FETCH curvar=%d\n", stmt->curvar);
671
672         dump_indent += 2;
673         if (stmt->rec != NULL)
674         {
675                 dump_ind();
676                 printf("    target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
677         }
678         if (stmt->row != NULL)
679         {
680                 dump_ind();
681                 printf("    target = %d %s\n", stmt->row->rowno, stmt->row->refname);
682         }
683         dump_indent -= 2;
684
685 }
686
687 static void
688 dump_close(PLpgSQL_stmt_close * stmt)
689 {
690         dump_ind();
691         printf("CLOSE curvar=%d\n", stmt->curvar);
692 }
693
694 static void
695 dump_exit(PLpgSQL_stmt_exit * stmt)
696 {
697         dump_ind();
698         printf("EXIT lbl='%s'", stmt->label);
699         if (stmt->cond != NULL)
700         {
701                 printf(" WHEN ");
702                 dump_expr(stmt->cond);
703         }
704         printf("\n");
705 }
706
707 static void
708 dump_return(PLpgSQL_stmt_return * stmt)
709 {
710         dump_ind();
711         printf("RETURN ");
712         if (stmt->retrecno > 0)
713                 printf("record %d", stmt->retrecno);
714         else
715         {
716                 if (stmt->expr == NULL)
717                         printf("NULL");
718                 else
719                         dump_expr(stmt->expr);
720         }
721         printf("\n");
722 }
723
724 static void
725 dump_raise(PLpgSQL_stmt_raise * stmt)
726 {
727         int                     i;
728
729         dump_ind();
730         printf("RAISE '%s'", stmt->message);
731         for (i = 0; i < stmt->nparams; i++)
732                 printf(" %d", stmt->params[i]);
733         printf("\n");
734 }
735
736 static void
737 dump_execsql(PLpgSQL_stmt_execsql * stmt)
738 {
739         dump_ind();
740         printf("EXECSQL ");
741         dump_expr(stmt->sqlstmt);
742         printf("\n");
743 }
744
745 static void
746 dump_dynexecute(PLpgSQL_stmt_dynexecute * stmt)
747 {
748         dump_ind();
749         printf("EXECUTE ");
750         dump_expr(stmt->query);
751         printf("\n");
752 }
753
754 static void
755 dump_dynfors(PLpgSQL_stmt_dynfors * stmt)
756 {
757         int                     i;
758
759         dump_ind();
760         printf("FORS %s EXECUTE ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
761         dump_expr(stmt->query);
762         printf("\n");
763
764         dump_indent += 2;
765         for (i = 0; i < stmt->body->stmts_used; i++)
766                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
767         dump_indent -= 2;
768
769         dump_ind();
770         printf("    ENDFORS\n");
771 }
772
773 static void
774 dump_getdiag(PLpgSQL_stmt_getdiag * stmt)
775 {
776         int                     i;
777
778         dump_ind();
779         printf("GET DIAGNOSTICS ");
780         for (i = 0; i < stmt->ndtitems; i++)
781         {
782                 PLpgSQL_diag_item *dtitem = &stmt->dtitems[i];
783
784                 if (i != 0)
785                         printf(", ");
786
787                 printf("{var %d} = ", dtitem->target);
788
789                 switch (dtitem->item)
790                 {
791                         case PLPGSQL_GETDIAG_ROW_COUNT:
792                                 printf("ROW_COUNT");
793                                 break;
794
795                         case PLPGSQL_GETDIAG_RESULT_OID:
796                                 printf("RESULT_OID");
797                                 break;
798
799                         default:
800                                 printf("???");
801                                 break;
802                 }
803         }
804         printf("\n");
805 }
806
807 static void
808 dump_expr(PLpgSQL_expr * expr)
809 {
810         int                     i;
811
812         printf("'%s", expr->query);
813         if (expr->nparams > 0)
814         {
815                 printf(" {");
816                 for (i = 0; i < expr->nparams; i++)
817                 {
818                         if (i > 0)
819                                 printf(", ");
820                         printf("$%d=%d", i + 1, expr->params[i]);
821                 }
822                 printf("}");
823         }
824         printf("'");
825 }
826
827 void
828 plpgsql_dumptree(PLpgSQL_function * func)
829 {
830         int                     i;
831         PLpgSQL_datum *d;
832
833         printf("\nExecution tree of successfully compiled PL/pgSQL function %s:\n",
834                    func->fn_name);
835
836         printf("\nFunctions data area:\n");
837         for (i = 0; i < func->ndatums; i++)
838         {
839                 d = func->datums[i];
840
841                 printf("    entry %d: ", i);
842                 switch (d->dtype)
843                 {
844                         case PLPGSQL_DTYPE_VAR:
845                                 {
846                                         PLpgSQL_var *var = (PLpgSQL_var *) d;
847
848                                         printf("VAR %-16s type %s (typoid %u) atttypmod %d\n",
849                                                    var->refname, var->datatype->typname,
850                                                    var->datatype->typoid,
851                                                    var->datatype->atttypmod);
852                                         if (var->isconst)
853                                                 printf("                                  CONSTANT\n");
854                                         if (var->notnull)
855                                                 printf("                                  NOT NULL\n");
856                                         if (var->default_val != NULL)
857                                         {
858                                                 printf("                                  DEFAULT ");
859                                                 dump_expr(var->default_val);
860                                                 printf("\n");
861                                         }
862                                         if (var->cursor_explicit_expr != NULL)
863                                         {
864                                                 if (var->cursor_explicit_argrow >= 0)
865                                                         printf("                                  CURSOR argument row %d\n", var->cursor_explicit_argrow);
866
867                                                 printf("                                  CURSOR IS ");
868                                                 dump_expr(var->cursor_explicit_expr);
869                                                 printf("\n");
870                                         }
871                                 }
872                                 break;
873                         case PLPGSQL_DTYPE_ROW:
874                                 {
875                                         PLpgSQL_row *row = (PLpgSQL_row *) d;
876                                         int                     i;
877
878                                         printf("ROW %-16s fields", row->refname);
879                                         for (i = 0; i < row->nfields; i++)
880                                         {
881                                                 printf(" %s=var %d", row->fieldnames[i],
882                                                            row->varnos[i]);
883                                         }
884                                         printf("\n");
885                                 }
886                                 break;
887                         case PLPGSQL_DTYPE_REC:
888                                 printf("REC %s\n", ((PLpgSQL_rec *) d)->refname);
889                                 break;
890                         case PLPGSQL_DTYPE_RECFIELD:
891                                 printf("RECFIELD %-16s of REC %d\n", ((PLpgSQL_recfield *) d)->fieldname, ((PLpgSQL_recfield *) d)->recno);
892                                 break;
893                         case PLPGSQL_DTYPE_TRIGARG:
894                                 printf("TRIGARG ");
895                                 dump_expr(((PLpgSQL_trigarg *) d)->argnum);
896                                 printf("\n");
897                                 break;
898                         default:
899                                 printf("??? unknown data type %d\n", d->dtype);
900                 }
901         }
902         printf("\nFunctions statements:\n");
903
904         dump_indent = 0;
905         printf("%3d:", func->action->lineno);
906         dump_block(func->action);
907         printf("\nEnd of execution tree of function %s\n\n", func->fn_name);
908 }