]> granicus.if.org Git - postgresql/blob - src/pl/plpgsql/src/pl_funcs.c
Rearrange plpgsql parsing to simplify and speed it up a bit.
[postgresql] / src / pl / plpgsql / src / pl_funcs.c
1 /*-------------------------------------------------------------------------
2  *
3  * pl_funcs.c           - Misc functions for the PL/pgSQL
4  *                        procedural language
5  *
6  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.85 2009/11/07 00:52:26 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 #include "plpgsql.h"
17
18 #include <ctype.h>
19
20 #include "parser/scansup.h"
21
22
23 /* ----------
24  * Local variables for namespace handling
25  *
26  * The namespace structure actually forms a tree, of which only one linear
27  * list or "chain" (from the youngest item to the root) is accessible from
28  * any one plpgsql statement.  During initial parsing of a function, ns_top
29  * points to the youngest item accessible from the block currently being
30  * parsed.  We store the entire tree, however, since at runtime we will need
31  * to access the chain that's relevant to any one statement.
32  *
33  * Block boundaries in the namespace chain are marked by PLPGSQL_NSTYPE_LABEL
34  * items.
35  * ----------
36  */
37 static PLpgSQL_nsitem *ns_top = NULL;
38
39
40 /* ----------
41  * plpgsql_ns_init                      Initialize namespace processing for a new function
42  * ----------
43  */
44 void
45 plpgsql_ns_init(void)
46 {
47         ns_top = NULL;
48 }
49
50
51 /* ----------
52  * plpgsql_ns_push                      Create a new namespace level
53  * ----------
54  */
55 void
56 plpgsql_ns_push(const char *label)
57 {
58         if (label == NULL)
59                 label = "";
60         plpgsql_ns_additem(PLPGSQL_NSTYPE_LABEL, 0, label);
61 }
62
63
64 /* ----------
65  * plpgsql_ns_pop                       Pop entries back to (and including) the last label
66  * ----------
67  */
68 void
69 plpgsql_ns_pop(void)
70 {
71         Assert(ns_top != NULL);
72         while (ns_top->itemtype != PLPGSQL_NSTYPE_LABEL)
73                 ns_top = ns_top->prev;
74         ns_top = ns_top->prev;
75 }
76
77
78 /* ----------
79  * plpgsql_ns_top                       Fetch the current namespace chain end
80  * ----------
81  */
82 PLpgSQL_nsitem *
83 plpgsql_ns_top(void)
84 {
85         return ns_top;
86 }
87
88
89 /* ----------
90  * plpgsql_ns_additem           Add an item to the current namespace chain
91  * ----------
92  */
93 void
94 plpgsql_ns_additem(int itemtype, int itemno, const char *name)
95 {
96         PLpgSQL_nsitem *nse;
97
98         Assert(name != NULL);
99         /* first item added must be a label */
100         Assert(ns_top != NULL || itemtype == PLPGSQL_NSTYPE_LABEL);
101
102         nse = palloc(sizeof(PLpgSQL_nsitem) + strlen(name));
103         nse->itemtype = itemtype;
104         nse->itemno = itemno;
105         nse->prev = ns_top;
106         strcpy(nse->name, name);
107         ns_top = nse;
108 }
109
110
111 /* ----------
112  * plpgsql_ns_lookup            Lookup an identifier in the given namespace chain
113  *
114  * Note that this only searches for variables, not labels.
115  *
116  * If localmode is TRUE, only the topmost block level is searched.
117  *
118  * name1 must be non-NULL.      Pass NULL for name2 and/or name3 if parsing a name
119  * with fewer than three components.
120  *
121  * If names_used isn't NULL, *names_used receives the number of names
122  * matched: 0 if no match, 1 if name1 matched an unqualified variable name,
123  * 2 if name1 and name2 matched a block label + variable name.
124  *
125  * Note that name3 is never directly matched to anything.  However, if it
126  * isn't NULL, we will disregard qualified matches to scalar variables.
127  * Similarly, if name2 isn't NULL, we disregard unqualified matches to
128  * scalar variables.
129  * ----------
130  */
131 PLpgSQL_nsitem *
132 plpgsql_ns_lookup(PLpgSQL_nsitem *ns_cur, bool localmode,
133                                   const char *name1, const char *name2, const char *name3,
134                                   int *names_used)
135 {
136         /* Outer loop iterates once per block level in the namespace chain */
137         while (ns_cur != NULL)
138         {
139                 PLpgSQL_nsitem *nsitem;
140
141                 /* Check this level for unqualified match to variable name */
142                 for (nsitem = ns_cur;
143                          nsitem->itemtype != PLPGSQL_NSTYPE_LABEL;
144                          nsitem = nsitem->prev)
145                 {
146                         if (strcmp(nsitem->name, name1) == 0)
147                         {
148                                 if (name2 == NULL ||
149                                         nsitem->itemtype != PLPGSQL_NSTYPE_VAR)
150                                 {
151                                         if (names_used)
152                                                 *names_used = 1;
153                                         return nsitem;
154                                 }
155                         }
156                 }
157
158                 /* Check this level for qualified match to variable name */
159                 if (name2 != NULL &&
160                         strcmp(nsitem->name, name1) == 0)
161                 {
162                         for (nsitem = ns_cur;
163                                  nsitem->itemtype != PLPGSQL_NSTYPE_LABEL;
164                                  nsitem = nsitem->prev)
165                         {
166                                 if (strcmp(nsitem->name, name2) == 0)
167                                 {
168                                         if (name3 == NULL ||
169                                                 nsitem->itemtype != PLPGSQL_NSTYPE_VAR)
170                                         {
171                                                 if (names_used)
172                                                         *names_used = 2;
173                                                 return nsitem;
174                                         }
175                                 }
176                         }
177                 }
178
179                 if (localmode)
180                         break;                          /* do not look into upper levels */
181
182                 ns_cur = nsitem->prev;
183         }
184
185         /* This is just to suppress possibly-uninitialized-variable warnings */
186         if (names_used)
187                 *names_used = 0;
188         return NULL;                            /* No match found */
189 }
190
191
192 /* ----------
193  * plpgsql_ns_lookup_label              Lookup a label in the given namespace chain
194  * ----------
195  */
196 PLpgSQL_nsitem *
197 plpgsql_ns_lookup_label(PLpgSQL_nsitem *ns_cur, const char *name)
198 {
199         while (ns_cur != NULL)
200         {
201                 if (ns_cur->itemtype == PLPGSQL_NSTYPE_LABEL &&
202                         strcmp(ns_cur->name, name) == 0)
203                         return ns_cur;
204                 ns_cur = ns_cur->prev;
205         }
206
207         return NULL;                            /* label not found */
208 }
209
210
211 /* ----------
212  * plpgsql_convert_ident
213  *
214  * Convert a possibly-qualified identifier to internal form: handle
215  * double quotes, translate to lower case where not inside quotes,
216  * truncate to NAMEDATALEN.
217  *
218  * There may be several identifiers separated by dots and optional
219  * whitespace.  Each one is converted to a separate palloc'd string.
220  * The caller passes the expected number of identifiers, as well as
221  * a char* array to hold them.  It is an error if we find the wrong
222  * number of identifiers (cf grammar processing of fori_varname).
223  *
224  * NOTE: the input string has already been accepted by the flex lexer,
225  * so we don't need a heckuva lot of error checking here.
226  * ----------
227  */
228 void
229 plpgsql_convert_ident(const char *s, char **output, int numidents)
230 {
231         const char *sstart = s;
232         int                     identctr = 0;
233
234         /* Outer loop over identifiers */
235         while (*s)
236         {
237                 char       *curident;
238                 char       *cp;
239
240                 /* Process current identifier */
241
242                 if (*s == '"')
243                 {
244                         /* Quoted identifier: copy, collapsing out doubled quotes */
245
246                         curident = palloc(strlen(s) + 1);       /* surely enough room */
247                         cp = curident;
248                         s++;
249                         while (*s)
250                         {
251                                 if (*s == '"')
252                                 {
253                                         if (s[1] != '"')
254                                                 break;
255                                         s++;
256                                 }
257                                 *cp++ = *s++;
258                         }
259                         if (*s != '"')          /* should not happen if lexer checked */
260                                 ereport(ERROR,
261                                                 (errcode(ERRCODE_SYNTAX_ERROR),
262                                            errmsg("unterminated \" in identifier: %s", sstart)));
263                         s++;
264                         *cp = '\0';
265                         /* Truncate to NAMEDATALEN */
266                         truncate_identifier(curident, cp - curident, false);
267                 }
268                 else
269                 {
270                         /* Normal identifier: extends till dot or whitespace */
271                         const char *thisstart = s;
272
273                         while (*s && *s != '.' && !scanner_isspace(*s))
274                                 s++;
275                         /* Downcase and truncate to NAMEDATALEN */
276                         curident = downcase_truncate_identifier(thisstart, s - thisstart,
277                                                                                                         false);
278                 }
279
280                 /* Pass ident to caller */
281                 if (identctr < numidents)
282                         output[identctr++] = curident;
283                 else
284                         ereport(ERROR,
285                                         (errcode(ERRCODE_SYNTAX_ERROR),
286                                          errmsg("qualified identifier cannot be used here: %s",
287                                                         sstart)));
288
289                 /* If not done, skip whitespace, dot, whitespace */
290                 if (*s)
291                 {
292                         while (*s && scanner_isspace(*s))
293                                 s++;
294                         if (*s++ != '.')
295                                 elog(ERROR, "expected dot between identifiers: %s", sstart);
296                         while (*s && scanner_isspace(*s))
297                                 s++;
298                         if (*s == '\0')
299                                 elog(ERROR, "expected another identifier: %s", sstart);
300                 }
301         }
302
303         if (identctr != numidents)
304                 elog(ERROR, "improperly qualified identifier: %s",
305                          sstart);
306 }
307
308
309 /*
310  * Statement type as a string, for use in error messages etc.
311  */
312 const char *
313 plpgsql_stmt_typename(PLpgSQL_stmt *stmt)
314 {
315         switch ((enum PLpgSQL_stmt_types) stmt->cmd_type)
316         {
317                 case PLPGSQL_STMT_BLOCK:
318                         return _("statement block");
319                 case PLPGSQL_STMT_ASSIGN:
320                         return _("assignment");
321                 case PLPGSQL_STMT_IF:
322                         return "IF";
323                 case PLPGSQL_STMT_CASE:
324                         return "CASE";
325                 case PLPGSQL_STMT_LOOP:
326                         return "LOOP";
327                 case PLPGSQL_STMT_WHILE:
328                         return "WHILE";
329                 case PLPGSQL_STMT_FORI:
330                         return _("FOR with integer loop variable");
331                 case PLPGSQL_STMT_FORS:
332                         return _("FOR over SELECT rows");
333                 case PLPGSQL_STMT_FORC:
334                         return _("FOR over cursor");
335                 case PLPGSQL_STMT_EXIT:
336                         return "EXIT";
337                 case PLPGSQL_STMT_RETURN:
338                         return "RETURN";
339                 case PLPGSQL_STMT_RETURN_NEXT:
340                         return "RETURN NEXT";
341                 case PLPGSQL_STMT_RETURN_QUERY:
342                         return "RETURN QUERY";
343                 case PLPGSQL_STMT_RAISE:
344                         return "RAISE";
345                 case PLPGSQL_STMT_EXECSQL:
346                         return _("SQL statement");
347                 case PLPGSQL_STMT_DYNEXECUTE:
348                         return _("EXECUTE statement");
349                 case PLPGSQL_STMT_DYNFORS:
350                         return _("FOR over EXECUTE statement");
351                 case PLPGSQL_STMT_GETDIAG:
352                         return "GET DIAGNOSTICS";
353                 case PLPGSQL_STMT_OPEN:
354                         return "OPEN";
355                 case PLPGSQL_STMT_FETCH:
356                         return "FETCH";
357                 case PLPGSQL_STMT_CLOSE:
358                         return "CLOSE";
359                 case PLPGSQL_STMT_PERFORM:
360                         return "PERFORM";
361         }
362
363         return "unknown";
364 }
365
366
367 /**********************************************************************
368  * Debug functions for analyzing the compiled code
369  **********************************************************************/
370 static int      dump_indent;
371
372 static void dump_ind(void);
373 static void dump_stmt(PLpgSQL_stmt *stmt);
374 static void dump_block(PLpgSQL_stmt_block *block);
375 static void dump_assign(PLpgSQL_stmt_assign *stmt);
376 static void dump_if(PLpgSQL_stmt_if *stmt);
377 static void dump_case(PLpgSQL_stmt_case *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_forc(PLpgSQL_stmt_forc *stmt);
383 static void dump_exit(PLpgSQL_stmt_exit *stmt);
384 static void dump_return(PLpgSQL_stmt_return *stmt);
385 static void dump_return_next(PLpgSQL_stmt_return_next *stmt);
386 static void dump_return_query(PLpgSQL_stmt_return_query *stmt);
387 static void dump_raise(PLpgSQL_stmt_raise *stmt);
388 static void dump_execsql(PLpgSQL_stmt_execsql *stmt);
389 static void dump_dynexecute(PLpgSQL_stmt_dynexecute *stmt);
390 static void dump_dynfors(PLpgSQL_stmt_dynfors *stmt);
391 static void dump_getdiag(PLpgSQL_stmt_getdiag *stmt);
392 static void dump_open(PLpgSQL_stmt_open *stmt);
393 static void dump_fetch(PLpgSQL_stmt_fetch *stmt);
394 static void dump_cursor_direction(PLpgSQL_stmt_fetch *stmt);
395 static void dump_close(PLpgSQL_stmt_close *stmt);
396 static void dump_perform(PLpgSQL_stmt_perform *stmt);
397 static void dump_expr(PLpgSQL_expr *expr);
398
399
400 static void
401 dump_ind(void)
402 {
403         int                     i;
404
405         for (i = 0; i < dump_indent; i++)
406                 printf(" ");
407 }
408
409 static void
410 dump_stmt(PLpgSQL_stmt *stmt)
411 {
412         printf("%3d:", stmt->lineno);
413         switch ((enum PLpgSQL_stmt_types) stmt->cmd_type)
414         {
415                 case PLPGSQL_STMT_BLOCK:
416                         dump_block((PLpgSQL_stmt_block *) stmt);
417                         break;
418                 case PLPGSQL_STMT_ASSIGN:
419                         dump_assign((PLpgSQL_stmt_assign *) stmt);
420                         break;
421                 case PLPGSQL_STMT_IF:
422                         dump_if((PLpgSQL_stmt_if *) stmt);
423                         break;
424                 case PLPGSQL_STMT_CASE:
425                         dump_case((PLpgSQL_stmt_case *) stmt);
426                         break;
427                 case PLPGSQL_STMT_LOOP:
428                         dump_loop((PLpgSQL_stmt_loop *) stmt);
429                         break;
430                 case PLPGSQL_STMT_WHILE:
431                         dump_while((PLpgSQL_stmt_while *) stmt);
432                         break;
433                 case PLPGSQL_STMT_FORI:
434                         dump_fori((PLpgSQL_stmt_fori *) stmt);
435                         break;
436                 case PLPGSQL_STMT_FORS:
437                         dump_fors((PLpgSQL_stmt_fors *) stmt);
438                         break;
439                 case PLPGSQL_STMT_FORC:
440                         dump_forc((PLpgSQL_stmt_forc *) stmt);
441                         break;
442                 case PLPGSQL_STMT_EXIT:
443                         dump_exit((PLpgSQL_stmt_exit *) stmt);
444                         break;
445                 case PLPGSQL_STMT_RETURN:
446                         dump_return((PLpgSQL_stmt_return *) stmt);
447                         break;
448                 case PLPGSQL_STMT_RETURN_NEXT:
449                         dump_return_next((PLpgSQL_stmt_return_next *) stmt);
450                         break;
451                 case PLPGSQL_STMT_RETURN_QUERY:
452                         dump_return_query((PLpgSQL_stmt_return_query *) stmt);
453                         break;
454                 case PLPGSQL_STMT_RAISE:
455                         dump_raise((PLpgSQL_stmt_raise *) stmt);
456                         break;
457                 case PLPGSQL_STMT_EXECSQL:
458                         dump_execsql((PLpgSQL_stmt_execsql *) stmt);
459                         break;
460                 case PLPGSQL_STMT_DYNEXECUTE:
461                         dump_dynexecute((PLpgSQL_stmt_dynexecute *) stmt);
462                         break;
463                 case PLPGSQL_STMT_DYNFORS:
464                         dump_dynfors((PLpgSQL_stmt_dynfors *) stmt);
465                         break;
466                 case PLPGSQL_STMT_GETDIAG:
467                         dump_getdiag((PLpgSQL_stmt_getdiag *) stmt);
468                         break;
469                 case PLPGSQL_STMT_OPEN:
470                         dump_open((PLpgSQL_stmt_open *) stmt);
471                         break;
472                 case PLPGSQL_STMT_FETCH:
473                         dump_fetch((PLpgSQL_stmt_fetch *) stmt);
474                         break;
475                 case PLPGSQL_STMT_CLOSE:
476                         dump_close((PLpgSQL_stmt_close *) stmt);
477                         break;
478                 case PLPGSQL_STMT_PERFORM:
479                         dump_perform((PLpgSQL_stmt_perform *) stmt);
480                         break;
481                 default:
482                         elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type);
483                         break;
484         }
485 }
486
487 static void
488 dump_stmts(List *stmts)
489 {
490         ListCell   *s;
491
492         dump_indent += 2;
493         foreach(s, stmts)
494                 dump_stmt((PLpgSQL_stmt *) lfirst(s));
495         dump_indent -= 2;
496 }
497
498 static void
499 dump_block(PLpgSQL_stmt_block *block)
500 {
501         char       *name;
502
503         if (block->label == NULL)
504                 name = "*unnamed*";
505         else
506                 name = block->label;
507
508         dump_ind();
509         printf("BLOCK <<%s>>\n", name);
510
511         dump_stmts(block->body);
512
513         if (block->exceptions)
514         {
515                 ListCell   *e;
516
517                 foreach(e, block->exceptions->exc_list)
518                 {
519                         PLpgSQL_exception *exc = (PLpgSQL_exception *) lfirst(e);
520                         PLpgSQL_condition *cond;
521
522                         dump_ind();
523                         printf("    EXCEPTION WHEN ");
524                         for (cond = exc->conditions; cond; cond = cond->next)
525                         {
526                                 if (cond != exc->conditions)
527                                         printf(" OR ");
528                                 printf("%s", cond->condname);
529                         }
530                         printf(" THEN\n");
531                         dump_stmts(exc->action);
532                 }
533         }
534
535         dump_ind();
536         printf("    END -- %s\n", name);
537 }
538
539 static void
540 dump_assign(PLpgSQL_stmt_assign *stmt)
541 {
542         dump_ind();
543         printf("ASSIGN var %d := ", stmt->varno);
544         dump_expr(stmt->expr);
545         printf("\n");
546 }
547
548 static void
549 dump_if(PLpgSQL_stmt_if *stmt)
550 {
551         dump_ind();
552         printf("IF ");
553         dump_expr(stmt->cond);
554         printf(" THEN\n");
555
556         dump_stmts(stmt->true_body);
557
558         if (stmt->false_body != NIL)
559         {
560                 dump_ind();
561                 printf("    ELSE\n");
562                 dump_stmts(stmt->false_body);
563         }
564
565         dump_ind();
566         printf("    ENDIF\n");
567 }
568
569 static void
570 dump_case(PLpgSQL_stmt_case *stmt)
571 {
572         ListCell   *l;
573
574         dump_ind();
575         printf("CASE %d ", stmt->t_varno);
576         if (stmt->t_expr)
577                 dump_expr(stmt->t_expr);
578         printf("\n");
579         dump_indent += 6;
580         foreach(l, stmt->case_when_list)
581         {
582                 PLpgSQL_case_when *cwt = (PLpgSQL_case_when *) lfirst(l);
583
584                 dump_ind();
585                 printf("WHEN ");
586                 dump_expr(cwt->expr);
587                 printf("\n");
588                 dump_ind();
589                 printf("THEN\n");
590                 dump_indent += 2;
591                 dump_stmts(cwt->stmts);
592                 dump_indent -= 2;
593         }
594         if (stmt->have_else)
595         {
596                 dump_ind();
597                 printf("ELSE\n");
598                 dump_indent += 2;
599                 dump_stmts(stmt->else_stmts);
600                 dump_indent -= 2;
601         }
602         dump_indent -= 6;
603         dump_ind();
604         printf("    ENDCASE\n");
605 }
606
607 static void
608 dump_loop(PLpgSQL_stmt_loop *stmt)
609 {
610         dump_ind();
611         printf("LOOP\n");
612
613         dump_stmts(stmt->body);
614
615         dump_ind();
616         printf("    ENDLOOP\n");
617 }
618
619 static void
620 dump_while(PLpgSQL_stmt_while *stmt)
621 {
622         dump_ind();
623         printf("WHILE ");
624         dump_expr(stmt->cond);
625         printf("\n");
626
627         dump_stmts(stmt->body);
628
629         dump_ind();
630         printf("    ENDWHILE\n");
631 }
632
633 static void
634 dump_fori(PLpgSQL_stmt_fori *stmt)
635 {
636         dump_ind();
637         printf("FORI %s %s\n", stmt->var->refname, (stmt->reverse) ? "REVERSE" : "NORMAL");
638
639         dump_indent += 2;
640         dump_ind();
641         printf("    lower = ");
642         dump_expr(stmt->lower);
643         printf("\n");
644         dump_ind();
645         printf("    upper = ");
646         dump_expr(stmt->upper);
647         printf("\n");
648         dump_ind();
649         printf("    step = ");
650         dump_expr(stmt->step);
651         printf("\n");
652         dump_indent -= 2;
653
654         dump_stmts(stmt->body);
655
656         dump_ind();
657         printf("    ENDFORI\n");
658 }
659
660 static void
661 dump_fors(PLpgSQL_stmt_fors *stmt)
662 {
663         dump_ind();
664         printf("FORS %s ", (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
665         dump_expr(stmt->query);
666         printf("\n");
667
668         dump_stmts(stmt->body);
669
670         dump_ind();
671         printf("    ENDFORS\n");
672 }
673
674 static void
675 dump_forc(PLpgSQL_stmt_forc *stmt)
676 {
677         dump_ind();
678         printf("FORC %s ", stmt->rec->refname);
679         printf("curvar=%d\n", stmt->curvar);
680
681         dump_indent += 2;
682         if (stmt->argquery != NULL)
683         {
684                 dump_ind();
685                 printf("  arguments = ");
686                 dump_expr(stmt->argquery);
687                 printf("\n");
688         }
689         dump_indent -= 2;
690
691         dump_stmts(stmt->body);
692
693         dump_ind();
694         printf("    ENDFORC\n");
695 }
696
697 static void
698 dump_open(PLpgSQL_stmt_open *stmt)
699 {
700         dump_ind();
701         printf("OPEN curvar=%d\n", stmt->curvar);
702
703         dump_indent += 2;
704         if (stmt->argquery != NULL)
705         {
706                 dump_ind();
707                 printf("  arguments = '");
708                 dump_expr(stmt->argquery);
709                 printf("'\n");
710         }
711         if (stmt->query != NULL)
712         {
713                 dump_ind();
714                 printf("  query = '");
715                 dump_expr(stmt->query);
716                 printf("'\n");
717         }
718         if (stmt->dynquery != NULL)
719         {
720                 dump_ind();
721                 printf("  execute = '");
722                 dump_expr(stmt->dynquery);
723                 printf("'\n");
724         }
725         dump_indent -= 2;
726
727 }
728
729 static void
730 dump_fetch(PLpgSQL_stmt_fetch *stmt)
731 {
732         dump_ind();
733
734         if (!stmt->is_move)
735         {
736                 printf("FETCH curvar=%d\n", stmt->curvar);
737                 dump_cursor_direction(stmt);
738
739                 dump_indent += 2;
740                 if (stmt->rec != NULL)
741                 {
742                         dump_ind();
743                         printf("    target = %d %s\n", stmt->rec->dno, stmt->rec->refname);
744                 }
745                 if (stmt->row != NULL)
746                 {
747                         dump_ind();
748                         printf("    target = %d %s\n", stmt->row->dno, stmt->row->refname);
749                 }
750                 dump_indent -= 2;
751         }
752         else
753         {
754                 printf("MOVE curvar=%d\n", stmt->curvar);
755                 dump_cursor_direction(stmt);
756         }
757 }
758
759 static void
760 dump_cursor_direction(PLpgSQL_stmt_fetch *stmt)
761 {
762         dump_indent += 2;
763         dump_ind();
764         switch (stmt->direction)
765         {
766                 case FETCH_FORWARD:
767                         printf("    FORWARD ");
768                         break;
769                 case FETCH_BACKWARD:
770                         printf("    BACKWARD ");
771                         break;
772                 case FETCH_ABSOLUTE:
773                         printf("    ABSOLUTE ");
774                         break;
775                 case FETCH_RELATIVE:
776                         printf("    RELATIVE ");
777                         break;
778                 default:
779                         printf("??? unknown cursor direction %d", stmt->direction);
780         }
781
782         if (stmt->expr)
783         {
784                 dump_expr(stmt->expr);
785                 printf("\n");
786         }
787         else
788                 printf("%ld\n", stmt->how_many);
789
790         dump_indent -= 2;
791 }
792
793 static void
794 dump_close(PLpgSQL_stmt_close *stmt)
795 {
796         dump_ind();
797         printf("CLOSE curvar=%d\n", stmt->curvar);
798 }
799
800 static void
801 dump_perform(PLpgSQL_stmt_perform *stmt)
802 {
803         dump_ind();
804         printf("PERFORM expr = ");
805         dump_expr(stmt->expr);
806         printf("\n");
807 }
808
809 static void
810 dump_exit(PLpgSQL_stmt_exit *stmt)
811 {
812         dump_ind();
813         printf("%s", stmt->is_exit ? "EXIT" : "CONTINUE");
814         if (stmt->label != NULL)
815                 printf(" label='%s'", stmt->label);
816         if (stmt->cond != NULL)
817         {
818                 printf(" WHEN ");
819                 dump_expr(stmt->cond);
820         }
821         printf("\n");
822 }
823
824 static void
825 dump_return(PLpgSQL_stmt_return *stmt)
826 {
827         dump_ind();
828         printf("RETURN ");
829         if (stmt->retvarno >= 0)
830                 printf("variable %d", stmt->retvarno);
831         else if (stmt->expr != NULL)
832                 dump_expr(stmt->expr);
833         else
834                 printf("NULL");
835         printf("\n");
836 }
837
838 static void
839 dump_return_next(PLpgSQL_stmt_return_next *stmt)
840 {
841         dump_ind();
842         printf("RETURN NEXT ");
843         if (stmt->retvarno >= 0)
844                 printf("variable %d", stmt->retvarno);
845         else if (stmt->expr != NULL)
846                 dump_expr(stmt->expr);
847         else
848                 printf("NULL");
849         printf("\n");
850 }
851
852 static void
853 dump_return_query(PLpgSQL_stmt_return_query *stmt)
854 {
855         dump_ind();
856         if (stmt->query)
857         {
858                 printf("RETURN QUERY ");
859                 dump_expr(stmt->query);
860                 printf("\n");
861         }
862         else
863         {
864                 printf("RETURN QUERY EXECUTE ");
865                 dump_expr(stmt->dynquery);
866                 printf("\n");
867                 if (stmt->params != NIL)
868                 {
869                         ListCell   *lc;
870                         int                     i;
871
872                         dump_indent += 2;
873                         dump_ind();
874                         printf("    USING\n");
875                         dump_indent += 2;
876                         i = 1;
877                         foreach(lc, stmt->params)
878                         {
879                                 dump_ind();
880                                 printf("    parameter $%d: ", i++);
881                                 dump_expr((PLpgSQL_expr *) lfirst(lc));
882                                 printf("\n");
883                         }
884                         dump_indent -= 4;
885                 }
886         }
887 }
888
889 static void
890 dump_raise(PLpgSQL_stmt_raise *stmt)
891 {
892         ListCell   *lc;
893         int                     i = 0;
894
895         dump_ind();
896         printf("RAISE level=%d", stmt->elog_level);
897         if (stmt->condname)
898                 printf(" condname='%s'", stmt->condname);
899         if (stmt->message)
900                 printf(" message='%s'", stmt->message);
901         printf("\n");
902         dump_indent += 2;
903         foreach(lc, stmt->params)
904         {
905                 dump_ind();
906                 printf("    parameter %d: ", i++);
907                 dump_expr((PLpgSQL_expr *) lfirst(lc));
908                 printf("\n");
909         }
910         if (stmt->options)
911         {
912                 dump_ind();
913                 printf("    USING\n");
914                 dump_indent += 2;
915                 foreach(lc, stmt->options)
916                 {
917                         PLpgSQL_raise_option *opt = (PLpgSQL_raise_option *) lfirst(lc);
918
919                         dump_ind();
920                         switch (opt->opt_type)
921                         {
922                                 case PLPGSQL_RAISEOPTION_ERRCODE:
923                                         printf("    ERRCODE = ");
924                                         break;
925                                 case PLPGSQL_RAISEOPTION_MESSAGE:
926                                         printf("    MESSAGE = ");
927                                         break;
928                                 case PLPGSQL_RAISEOPTION_DETAIL:
929                                         printf("    DETAIL = ");
930                                         break;
931                                 case PLPGSQL_RAISEOPTION_HINT:
932                                         printf("    HINT = ");
933                                         break;
934                         }
935                         dump_expr(opt->expr);
936                         printf("\n");
937                 }
938                 dump_indent -= 2;
939         }
940         dump_indent -= 2;
941 }
942
943 static void
944 dump_execsql(PLpgSQL_stmt_execsql *stmt)
945 {
946         dump_ind();
947         printf("EXECSQL ");
948         dump_expr(stmt->sqlstmt);
949         printf("\n");
950
951         dump_indent += 2;
952         if (stmt->rec != NULL)
953         {
954                 dump_ind();
955                 printf("    INTO%s target = %d %s\n",
956                            stmt->strict ? " STRICT" : "",
957                            stmt->rec->dno, stmt->rec->refname);
958         }
959         if (stmt->row != NULL)
960         {
961                 dump_ind();
962                 printf("    INTO%s target = %d %s\n",
963                            stmt->strict ? " STRICT" : "",
964                            stmt->row->dno, stmt->row->refname);
965         }
966         dump_indent -= 2;
967 }
968
969 static void
970 dump_dynexecute(PLpgSQL_stmt_dynexecute *stmt)
971 {
972         dump_ind();
973         printf("EXECUTE ");
974         dump_expr(stmt->query);
975         printf("\n");
976
977         dump_indent += 2;
978         if (stmt->rec != NULL)
979         {
980                 dump_ind();
981                 printf("    INTO%s target = %d %s\n",
982                            stmt->strict ? " STRICT" : "",
983                            stmt->rec->dno, stmt->rec->refname);
984         }
985         if (stmt->row != NULL)
986         {
987                 dump_ind();
988                 printf("    INTO%s target = %d %s\n",
989                            stmt->strict ? " STRICT" : "",
990                            stmt->row->dno, stmt->row->refname);
991         }
992         if (stmt->params != NIL)
993         {
994                 ListCell   *lc;
995                 int                     i;
996
997                 dump_ind();
998                 printf("    USING\n");
999                 dump_indent += 2;
1000                 i = 1;
1001                 foreach(lc, stmt->params)
1002                 {
1003                         dump_ind();
1004                         printf("    parameter %d: ", i++);
1005                         dump_expr((PLpgSQL_expr *) lfirst(lc));
1006                         printf("\n");
1007                 }
1008                 dump_indent -= 2;
1009         }
1010         dump_indent -= 2;
1011 }
1012
1013 static void
1014 dump_dynfors(PLpgSQL_stmt_dynfors *stmt)
1015 {
1016         dump_ind();
1017         printf("FORS %s EXECUTE ",
1018                    (stmt->rec != NULL) ? stmt->rec->refname : stmt->row->refname);
1019         dump_expr(stmt->query);
1020         printf("\n");
1021         if (stmt->params != NIL)
1022         {
1023                 ListCell   *lc;
1024                 int                     i;
1025
1026                 dump_indent += 2;
1027                 dump_ind();
1028                 printf("    USING\n");
1029                 dump_indent += 2;
1030                 i = 1;
1031                 foreach(lc, stmt->params)
1032                 {
1033                         dump_ind();
1034                         printf("    parameter $%d: ", i++);
1035                         dump_expr((PLpgSQL_expr *) lfirst(lc));
1036                         printf("\n");
1037                 }
1038                 dump_indent -= 4;
1039         }
1040         dump_stmts(stmt->body);
1041         dump_ind();
1042         printf("    ENDFORS\n");
1043 }
1044
1045 static void
1046 dump_getdiag(PLpgSQL_stmt_getdiag *stmt)
1047 {
1048         ListCell   *lc;
1049
1050         dump_ind();
1051         printf("GET DIAGNOSTICS ");
1052         foreach(lc, stmt->diag_items)
1053         {
1054                 PLpgSQL_diag_item *diag_item = (PLpgSQL_diag_item *) lfirst(lc);
1055
1056                 if (lc != list_head(stmt->diag_items))
1057                         printf(", ");
1058
1059                 printf("{var %d} = ", diag_item->target);
1060
1061                 switch (diag_item->kind)
1062                 {
1063                         case PLPGSQL_GETDIAG_ROW_COUNT:
1064                                 printf("ROW_COUNT");
1065                                 break;
1066
1067                         case PLPGSQL_GETDIAG_RESULT_OID:
1068                                 printf("RESULT_OID");
1069                                 break;
1070
1071                         default:
1072                                 printf("???");
1073                                 break;
1074                 }
1075         }
1076         printf("\n");
1077 }
1078
1079 static void
1080 dump_expr(PLpgSQL_expr *expr)
1081 {
1082         printf("'%s'", expr->query);
1083 }
1084
1085 void
1086 plpgsql_dumptree(PLpgSQL_function *func)
1087 {
1088         int                     i;
1089         PLpgSQL_datum *d;
1090
1091         printf("\nExecution tree of successfully compiled PL/pgSQL function %s:\n",
1092                    func->fn_name);
1093
1094         printf("\nFunction's data area:\n");
1095         for (i = 0; i < func->ndatums; i++)
1096         {
1097                 d = func->datums[i];
1098
1099                 printf("    entry %d: ", i);
1100                 switch (d->dtype)
1101                 {
1102                         case PLPGSQL_DTYPE_VAR:
1103                                 {
1104                                         PLpgSQL_var *var = (PLpgSQL_var *) d;
1105
1106                                         printf("VAR %-16s type %s (typoid %u) atttypmod %d\n",
1107                                                    var->refname, var->datatype->typname,
1108                                                    var->datatype->typoid,
1109                                                    var->datatype->atttypmod);
1110                                         if (var->isconst)
1111                                                 printf("                                  CONSTANT\n");
1112                                         if (var->notnull)
1113                                                 printf("                                  NOT NULL\n");
1114                                         if (var->default_val != NULL)
1115                                         {
1116                                                 printf("                                  DEFAULT ");
1117                                                 dump_expr(var->default_val);
1118                                                 printf("\n");
1119                                         }
1120                                         if (var->cursor_explicit_expr != NULL)
1121                                         {
1122                                                 if (var->cursor_explicit_argrow >= 0)
1123                                                         printf("                                  CURSOR argument row %d\n", var->cursor_explicit_argrow);
1124
1125                                                 printf("                                  CURSOR IS ");
1126                                                 dump_expr(var->cursor_explicit_expr);
1127                                                 printf("\n");
1128                                         }
1129                                 }
1130                                 break;
1131                         case PLPGSQL_DTYPE_ROW:
1132                                 {
1133                                         PLpgSQL_row *row = (PLpgSQL_row *) d;
1134                                         int                     i;
1135
1136                                         printf("ROW %-16s fields", row->refname);
1137                                         for (i = 0; i < row->nfields; i++)
1138                                         {
1139                                                 if (row->fieldnames[i])
1140                                                         printf(" %s=var %d", row->fieldnames[i],
1141                                                                    row->varnos[i]);
1142                                         }
1143                                         printf("\n");
1144                                 }
1145                                 break;
1146                         case PLPGSQL_DTYPE_REC:
1147                                 printf("REC %s\n", ((PLpgSQL_rec *) d)->refname);
1148                                 break;
1149                         case PLPGSQL_DTYPE_RECFIELD:
1150                                 printf("RECFIELD %-16s of REC %d\n",
1151                                            ((PLpgSQL_recfield *) d)->fieldname,
1152                                            ((PLpgSQL_recfield *) d)->recparentno);
1153                                 break;
1154                         case PLPGSQL_DTYPE_ARRAYELEM:
1155                                 printf("ARRAYELEM of VAR %d subscript ",
1156                                            ((PLpgSQL_arrayelem *) d)->arrayparentno);
1157                                 dump_expr(((PLpgSQL_arrayelem *) d)->subscript);
1158                                 printf("\n");
1159                                 break;
1160                         default:
1161                                 printf("??? unknown data type %d\n", d->dtype);
1162                 }
1163         }
1164         printf("\nFunction's statements:\n");
1165
1166         dump_indent = 0;
1167         printf("%3d:", func->action->lineno);
1168         dump_block(func->action);
1169         printf("\nEnd of execution tree of function %s\n\n", func->fn_name);
1170         fflush(stdout);
1171 }