]> granicus.if.org Git - postgresql/blob - src/pl/plpgsql/src/pl_funcs.c
Change plpgsql's GET DIAGNOSTICS statement to use SQL99-compatible
[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.10 2001/02/19 19:49:53 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 <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          */
231         if (label != NULL)
232         {
233                 for (ns = ns_current; ns != NULL; ns = ns->upper)
234                 {
235                         if (!strcmp(ns->items[0]->name, label))
236                         {
237                                 for (i = 1; i < ns->items_used; i++)
238                                 {
239                                         if (!strcmp(ns->items[i]->name, name))
240                                                 return ns->items[i];
241                                 }
242                                 return NULL;    /* name not found in specified label */
243                         }
244                 }
245                 return NULL;                    /* label not found */
246         }
247
248         /* ----------
249          * No label given, lookup for visible labels ignoring localmode
250          * ----------
251          */
252         for (ns = ns_current; ns != NULL; ns = ns->upper)
253         {
254                 if (!strcmp(ns->items[0]->name, name))
255                         return ns->items[0];
256         }
257
258         /* ----------
259          * Finally lookup name in the namestack
260          * ----------
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                 {
271                         return NULL;            /* name not found in current namespace */
272                 }
273         }
274
275         return NULL;
276 }
277
278
279 /* ----------
280  * plpgsql_ns_rename                    Rename a namespace entry
281  * ----------
282  */
283 void
284 plpgsql_ns_rename(char *oldname, char *newname)
285 {
286         PLpgSQL_ns *ns;
287         PLpgSQL_nsitem *newitem;
288         int                     i;
289
290         /* ----------
291          * Lookup in the current namespace only
292          * ----------
293          */
294         /* ----------
295          * Lookup name in the namestack
296          * ----------
297          */
298         for (ns = ns_current; ns != NULL; ns = ns->upper)
299         {
300                 for (i = 1; i < ns->items_used; i++)
301                 {
302                         if (!strcmp(ns->items[i]->name, oldname))
303                         {
304                                 newitem = palloc(sizeof(PLpgSQL_nsitem) + strlen(newname));
305                                 newitem->itemtype = ns->items[i]->itemtype;
306                                 newitem->itemno = ns->items[i]->itemno;
307                                 strcpy(newitem->name, newname);
308
309                                 pfree(oldname);
310                                 pfree(newname);
311
312                                 pfree(ns->items[i]);
313                                 ns->items[i] = newitem;
314                                 return;
315                         }
316                 }
317         }
318
319         elog(ERROR, "there is no variable '%s' in the current block", oldname);
320 }
321
322
323 /* ----------
324  * plpgsql_tolower                      Translate a string to lower case
325  *                                      but honor "" escaping.
326  * ----------
327  */
328 char *
329 plpgsql_tolower(char *s)
330 {
331         char       *ret;
332         char       *cp;
333
334         ret = palloc(strlen(s) + 1);
335         cp = ret;
336
337         while (*s)
338         {
339                 if (*s == '"')
340                 {
341                         s++;
342                         while (*s)
343                         {
344                                 if (*s == '"')
345                                         break;
346                                 *cp++ = *s++;
347                         }
348                         if (*s != '"')
349                         {
350                                 plpgsql_comperrinfo();
351                                 elog(ERROR, "unterminated \"");
352                         }
353                         s++;
354                 }
355                 else
356                 {
357                         if (isupper((unsigned char) *s))
358                                 *cp++ = tolower((unsigned char) *s++);
359                         else
360                                 *cp++ = *s++;
361                 }
362         }
363         *cp = '\0';
364
365         return ret;
366 }
367
368
369
370
371
372 /**********************************************************************
373  * Debug functions for analyzing the compiled code
374  **********************************************************************/
375 static int      dump_indent;
376
377 static void dump_ind();
378 static void dump_stmt(PLpgSQL_stmt * stmt);
379 static void dump_block(PLpgSQL_stmt_block * block);
380 static void dump_assign(PLpgSQL_stmt_assign * stmt);
381 static void dump_if(PLpgSQL_stmt_if * stmt);
382 static void dump_loop(PLpgSQL_stmt_loop * stmt);
383 static void dump_while(PLpgSQL_stmt_while * stmt);
384 static void dump_fori(PLpgSQL_stmt_fori * stmt);
385 static void dump_fors(PLpgSQL_stmt_fors * stmt);
386 static void dump_select(PLpgSQL_stmt_select * stmt);
387 static void dump_exit(PLpgSQL_stmt_exit * stmt);
388 static void dump_return(PLpgSQL_stmt_return * stmt);
389 static void dump_raise(PLpgSQL_stmt_raise * stmt);
390 static void dump_execsql(PLpgSQL_stmt_execsql * stmt);
391 static void dump_dynexecute(PLpgSQL_stmt_dynexecute * stmt);
392 static void dump_dynfors(PLpgSQL_stmt_dynfors * stmt);
393 static void dump_getdiag(PLpgSQL_stmt_getdiag * stmt);
394 static void dump_expr(PLpgSQL_expr * expr);
395
396
397 static void
398 dump_ind()
399 {
400         int                     i;
401
402         for (i = 0; i < dump_indent; i++)
403                 printf(" ");
404 }
405
406 static void
407 dump_stmt(PLpgSQL_stmt * stmt)
408 {
409         printf("%3d:", stmt->lineno);
410         switch (stmt->cmd_type)
411         {
412                 case PLPGSQL_STMT_BLOCK:
413                         dump_block((PLpgSQL_stmt_block *) stmt);
414                         break;
415                 case PLPGSQL_STMT_ASSIGN:
416                         dump_assign((PLpgSQL_stmt_assign *) stmt);
417                         break;
418                 case PLPGSQL_STMT_IF:
419                         dump_if((PLpgSQL_stmt_if *) stmt);
420                         break;
421                 case PLPGSQL_STMT_LOOP:
422                         dump_loop((PLpgSQL_stmt_loop *) stmt);
423                         break;
424                 case PLPGSQL_STMT_WHILE:
425                         dump_while((PLpgSQL_stmt_while *) stmt);
426                         break;
427                 case PLPGSQL_STMT_FORI:
428                         dump_fori((PLpgSQL_stmt_fori *) stmt);
429                         break;
430                 case PLPGSQL_STMT_FORS:
431                         dump_fors((PLpgSQL_stmt_fors *) stmt);
432                         break;
433                 case PLPGSQL_STMT_SELECT:
434                         dump_select((PLpgSQL_stmt_select *) stmt);
435                         break;
436                 case PLPGSQL_STMT_EXIT:
437                         dump_exit((PLpgSQL_stmt_exit *) stmt);
438                         break;
439                 case PLPGSQL_STMT_RETURN:
440                         dump_return((PLpgSQL_stmt_return *) stmt);
441                         break;
442                 case PLPGSQL_STMT_RAISE:
443                         dump_raise((PLpgSQL_stmt_raise *) stmt);
444                         break;
445                 case PLPGSQL_STMT_EXECSQL:
446                         dump_execsql((PLpgSQL_stmt_execsql *) stmt);
447                         break;
448                 case PLPGSQL_STMT_DYNEXECUTE:
449                         dump_dynexecute((PLpgSQL_stmt_dynexecute *) stmt);
450                         break;
451                 case PLPGSQL_STMT_DYNFORS:
452                         dump_dynfors((PLpgSQL_stmt_dynfors *) stmt);
453                         break;
454                 case PLPGSQL_STMT_GETDIAG:
455                         dump_getdiag((PLpgSQL_stmt_getdiag *) stmt);
456                         break;
457                 default:
458                         elog(ERROR, "plpgsql_dump: unknown cmd_type %d\n", stmt->cmd_type);
459                         break;
460         }
461 }
462
463 static void
464 dump_block(PLpgSQL_stmt_block * block)
465 {
466         int                     i;
467         char       *name;
468
469         if (block->label == NULL)
470                 name = "*unnamed*";
471         else
472                 name = block->label;
473
474         dump_ind();
475         printf("BLOCK <<%s>>\n", name);
476
477         dump_indent += 2;
478         for (i = 0; i < block->body->stmts_used; i++)
479                 dump_stmt((PLpgSQL_stmt *) (block->body->stmts[i]));
480         dump_indent -= 2;
481
482         dump_ind();
483         printf("    END -- %s\n", name);
484 }
485
486 static void
487 dump_assign(PLpgSQL_stmt_assign * stmt)
488 {
489         dump_ind();
490         printf("ASSIGN var %d := ", stmt->varno);
491         dump_expr(stmt->expr);
492         printf("\n");
493 }
494
495 static void
496 dump_if(PLpgSQL_stmt_if * stmt)
497 {
498         int                     i;
499
500         dump_ind();
501         printf("IF ");
502         dump_expr(stmt->cond);
503         printf(" THEN\n");
504
505         dump_indent += 2;
506         for (i = 0; i < stmt->true_body->stmts_used; i++)
507                 dump_stmt((PLpgSQL_stmt *) (stmt->true_body->stmts[i]));
508         dump_indent -= 2;
509
510         dump_ind();
511         printf("    ELSE\n");
512
513         dump_indent += 2;
514         for (i = 0; i < stmt->false_body->stmts_used; i++)
515                 dump_stmt((PLpgSQL_stmt *) (stmt->false_body->stmts[i]));
516         dump_indent -= 2;
517
518         dump_ind();
519         printf("    ENDIF\n");
520 }
521
522 static void
523 dump_loop(PLpgSQL_stmt_loop * stmt)
524 {
525         int                     i;
526
527         dump_ind();
528         printf("LOOP\n");
529
530         dump_indent += 2;
531         for (i = 0; i < stmt->body->stmts_used; i++)
532                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
533         dump_indent -= 2;
534
535         dump_ind();
536         printf("    ENDLOOP\n");
537 }
538
539 static void
540 dump_while(PLpgSQL_stmt_while * stmt)
541 {
542         int                     i;
543
544         dump_ind();
545         printf("WHILE ");
546         dump_expr(stmt->cond);
547         printf("\n");
548
549         dump_indent += 2;
550         for (i = 0; i < stmt->body->stmts_used; i++)
551                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
552         dump_indent -= 2;
553
554         dump_ind();
555         printf("    ENDWHILE\n");
556 }
557
558 static void
559 dump_fori(PLpgSQL_stmt_fori * stmt)
560 {
561         int                     i;
562
563         dump_ind();
564         printf("FORI %s %s\n", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL");
565
566         dump_indent += 2;
567         dump_ind();
568         printf("    lower = ");
569         dump_expr(stmt->lower);
570         printf("\n");
571         dump_ind();
572         printf("    upper = ");
573         dump_expr(stmt->upper);
574         printf("\n");
575
576         for (i = 0; i < stmt->body->stmts_used; i++)
577                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
578         dump_indent -= 2;
579
580         dump_ind();
581         printf("    ENDFORI\n");
582 }
583
584 static void
585 dump_fors(PLpgSQL_stmt_fors * stmt)
586 {
587         int                     i;
588
589         dump_ind();
590         printf("FORS %s ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
591         dump_expr(stmt->query);
592         printf("\n");
593
594         dump_indent += 2;
595         for (i = 0; i < stmt->body->stmts_used; i++)
596                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
597         dump_indent -= 2;
598
599         dump_ind();
600         printf("    ENDFORS\n");
601 }
602
603 static void
604 dump_select(PLpgSQL_stmt_select * stmt)
605 {
606         dump_ind();
607         printf("SELECT ");
608         dump_expr(stmt->query);
609         printf("\n");
610
611         dump_indent += 2;
612         if (stmt->rec != NULL)
613         {
614                 dump_ind();
615                 printf("    target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
616         }
617         if (stmt->row != NULL)
618         {
619                 dump_ind();
620                 printf("    target = %d %s\n", stmt->row->rowno, stmt->row->refname);
621         }
622         dump_indent -= 2;
623
624 }
625
626 static void
627 dump_exit(PLpgSQL_stmt_exit * stmt)
628 {
629         dump_ind();
630         printf("EXIT lbl='%s'", stmt->label);
631         if (stmt->cond != NULL)
632         {
633                 printf(" WHEN ");
634                 dump_expr(stmt->cond);
635         }
636         printf("\n");
637 }
638
639 static void
640 dump_return(PLpgSQL_stmt_return * stmt)
641 {
642         dump_ind();
643         printf("RETURN ");
644         if (stmt->retrecno > 0)
645                 printf("record %d", stmt->retrecno);
646         else
647         {
648                 if (stmt->expr == NULL)
649                         printf("NULL");
650                 else
651                         dump_expr(stmt->expr);
652         }
653         printf("\n");
654 }
655
656 static void
657 dump_raise(PLpgSQL_stmt_raise * stmt)
658 {
659         int                     i;
660
661         dump_ind();
662         printf("RAISE '%s'", stmt->message);
663         for (i = 0; i < stmt->nparams; i++)
664                 printf(" %d", stmt->params[i]);
665         printf("\n");
666 }
667
668 static void
669 dump_execsql(PLpgSQL_stmt_execsql * stmt)
670 {
671         dump_ind();
672         printf("EXECSQL ");
673         dump_expr(stmt->sqlstmt);
674         printf("\n");
675 }
676
677 static void
678 dump_dynexecute(PLpgSQL_stmt_dynexecute * stmt)
679 {
680         dump_ind();
681         printf("EXECUTE ");
682         dump_expr(stmt->query);
683         printf("\n");
684 }
685
686 static void
687 dump_dynfors(PLpgSQL_stmt_dynfors * stmt)
688 {
689         int                     i;
690
691         dump_ind();
692         printf("FORS %s EXECUTE ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
693         dump_expr(stmt->query);
694         printf("\n");
695
696         dump_indent += 2;
697         for (i = 0; i < stmt->body->stmts_used; i++)
698                 dump_stmt((PLpgSQL_stmt *) (stmt->body->stmts[i]));
699         dump_indent -= 2;
700
701         dump_ind();
702         printf("    ENDFORS\n");
703 }
704
705 static void
706 dump_getdiag(PLpgSQL_stmt_getdiag * stmt)
707 {
708         int                     i;
709
710         dump_ind();
711         printf("GET DIAGNOSTICS ");
712         for (i = 0; i < stmt->ndtitems; i++)
713         {
714                 PLpgSQL_diag_item *dtitem = & stmt->dtitems[i];
715
716                 if (i != 0)
717                         printf(", ");
718
719                 printf("{var %d} = ", dtitem->target);
720
721             switch (dtitem->item)
722                 {
723                     case PLPGSQL_GETDIAG_ROW_COUNT:
724                                 printf("ROW_COUNT");
725                                 break;
726
727                         case PLPGSQL_GETDIAG_RESULT_OID:
728                                 printf("RESULT_OID");
729                                 break;
730
731                         default:
732                             printf("???");
733                                 break;
734                 }
735         }
736         printf("\n");
737 }
738
739 static void
740 dump_expr(PLpgSQL_expr * expr)
741 {
742         int                     i;
743
744         printf("'%s", expr->query);
745         if (expr->nparams > 0)
746         {
747                 printf(" {");
748                 for (i = 0; i < expr->nparams; i++)
749                 {
750                         if (i > 0)
751                                 printf(", ");
752                         printf("$%d=%d", i + 1, expr->params[i]);
753                 }
754                 printf("}");
755         }
756         printf("'");
757 }
758
759 void
760 plpgsql_dumptree(PLpgSQL_function * func)
761 {
762         int                     i;
763         PLpgSQL_datum *d;
764
765         printf("\nExecution tree of successfully compiled PL/pgSQL function %s:\n",
766                    func->fn_name);
767
768         printf("\nFunctions data area:\n");
769         for (i = 0; i < func->ndatums; i++)
770         {
771                 d = func->datums[i];
772
773                 printf("    entry %d: ", i);
774                 switch (d->dtype)
775                 {
776                         case PLPGSQL_DTYPE_VAR:
777                                 {
778                                         PLpgSQL_var *var = (PLpgSQL_var *) d;
779
780                                         printf("VAR %-16s type %s (typoid %u) atttypmod %d\n",
781                                                    var->refname, var->datatype->typname,
782                                                    var->datatype->typoid,
783                                                    var->datatype->atttypmod);
784                                 }
785                                 break;
786                         case PLPGSQL_DTYPE_ROW:
787                                 {
788                                         PLpgSQL_row *row = (PLpgSQL_row *) d;
789                                         int                     i;
790
791                                         printf("ROW %-16s fields", row->refname);
792                                         for (i = 0; i < row->nfields; i++)
793                                         {
794                                                 printf(" %s=var %d", row->fieldnames[i],
795                                                            row->varnos[i]);
796                                         }
797                                         printf("\n");
798                                 }
799                                 break;
800                         case PLPGSQL_DTYPE_REC:
801                                 printf("REC %s\n", ((PLpgSQL_rec *) d)->refname);
802                                 break;
803                         case PLPGSQL_DTYPE_RECFIELD:
804                                 printf("RECFIELD %-16s of REC %d\n", ((PLpgSQL_recfield *) d)->fieldname, ((PLpgSQL_recfield *) d)->recno);
805                                 break;
806                         case PLPGSQL_DTYPE_TRIGARG:
807                                 printf("TRIGARG ");
808                                 dump_expr(((PLpgSQL_trigarg *) d)->argnum);
809                                 printf("\n");
810                                 break;
811                         default:
812                                 printf("??? unknown data type %d\n", d->dtype);
813                 }
814         }
815         printf("\nFunctions statements:\n");
816
817         dump_indent = 0;
818         printf("%3d:", func->action->lineno);
819         dump_block(func->action);
820         printf("\nEnd of execution tree of function %s\n\n", func->fn_name);
821 }