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