]> granicus.if.org Git - postgresql/blob - src/pl/plpgsql/src/gram.y
Fix so BSD yacc works on file.
[postgresql] / src / pl / plpgsql / src / gram.y
1 %{
2 /**********************************************************************
3  * gram.y               - Parser for the PL/pgSQL
4  *                        procedural language
5  *
6  * IDENTIFICATION
7  *    $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.5 1999/08/07 04:25:02 momjian Exp $
8  *
9  *    This software is copyrighted by Jan Wieck - Hamburg.
10  *
11  *    The author hereby grants permission  to  use,  copy,  modify,
12  *    distribute,  and  license this software and its documentation
13  *    for any purpose, provided that existing copyright notices are
14  *    retained  in  all  copies  and  that  this notice is included
15  *    verbatim in any distributions. No written agreement, license,
16  *    or  royalty  fee  is required for any of the authorized uses.
17  *    Modifications to this software may be  copyrighted  by  their
18  *    author  and  need  not  follow  the licensing terms described
19  *    here, provided that the new terms are  clearly  indicated  on
20  *    the first page of each file where they apply.
21  *
22  *    IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY
23  *    PARTY  FOR  DIRECT,   INDIRECT,   SPECIAL,   INCIDENTAL,   OR
24  *    CONSEQUENTIAL   DAMAGES  ARISING  OUT  OF  THE  USE  OF  THIS
25  *    SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
26  *    IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
27  *    DAMAGE.
28  *
29  *    THE  AUTHOR  AND  DISTRIBUTORS  SPECIFICALLY   DISCLAIM   ANY
30  *    WARRANTIES,  INCLUDING,  BUT  NOT  LIMITED  TO,  THE  IMPLIED
31  *    WARRANTIES  OF  MERCHANTABILITY,  FITNESS  FOR  A  PARTICULAR
32  *    PURPOSE,  AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON
33  *    AN "AS IS" BASIS, AND THE AUTHOR  AND  DISTRIBUTORS  HAVE  NO
34  *    OBLIGATION   TO   PROVIDE   MAINTENANCE,   SUPPORT,  UPDATES,
35  *    ENHANCEMENTS, OR MODIFICATIONS.
36  *
37  **********************************************************************/
38
39 #include "stdio.h"
40 #include "string.h"
41 #include "plpgsql.h"
42
43
44 static  PLpgSQL_expr    *read_sqlstmt(int until, char *s, char *sqlstart);
45 static  PLpgSQL_stmt    *make_select_stmt(void);
46 static  PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
47
48 %}
49
50 %union {
51         int32                   ival;
52         char                    *str;
53         struct {
54             char *name;
55             int  lineno;
56         }                       varname;
57         struct {
58             int  nalloc;
59             int  nused;
60             int  *dtnums;
61         }                       dtlist;
62         struct {
63             int  reverse;
64             PLpgSQL_expr *expr;
65         }                       forilow;
66         struct {
67             char *label;
68             int  n_initvars;
69             int  *initvarnos;
70         }                       declhdr;
71         PLpgSQL_type            *dtype;
72         PLpgSQL_var             *var;
73         PLpgSQL_row             *row;
74         PLpgSQL_rec             *rec;
75         PLpgSQL_recfield        *recfield;
76         PLpgSQL_trigarg         *trigarg;
77         PLpgSQL_expr            *expr;
78         PLpgSQL_stmt            *stmt;
79         PLpgSQL_stmts           *stmts;
80         PLpgSQL_stmt_block      *program;
81         PLpgSQL_nsitem          *nsitem;
82 }
83
84 %type <declhdr> decl_sect
85 %type <varname> decl_varname
86 %type <str>     decl_renname
87 %type <ival>    decl_const, decl_notnull, decl_atttypmod, decl_atttypmodval
88 %type <expr>    decl_defval
89 %type <dtype>   decl_datatype, decl_dtypename
90 %type <row>     decl_rowtype
91 %type <nsitem>  decl_aliasitem
92 %type <str>     decl_stmts, decl_stmt
93
94 %type <expr>    expr_until_semi, expr_until_then, expr_until_loop
95 %type <expr>    opt_exitcond
96
97 %type <ival>    assign_var
98 %type <var>     fori_var
99 %type <varname> fori_varname
100 %type <forilow> fori_lower
101 %type <rec>     fors_target
102
103 %type <str>     opt_lblname, opt_label
104 %type <str>     opt_exitlabel
105 %type <str>     execsql_start
106
107 %type <stmts>   proc_sect, proc_stmts, stmt_else, loop_body
108 %type <stmt>    proc_stmt, pl_block
109 %type <stmt>    stmt_assign, stmt_if, stmt_loop, stmt_while, stmt_exit
110 %type <stmt>    stmt_return, stmt_raise, stmt_execsql, stmt_fori
111 %type <stmt>    stmt_fors, stmt_select, stmt_perform
112
113 %type <dtlist>  raise_params
114 %type <ival>    raise_level, raise_param
115 %type <str>     raise_msg
116
117 %type <ival>    lno
118
119         /*
120          * Keyword tokens
121          */
122 %token  K_ALIAS
123 %token  K_ASSIGN
124 %token  K_BEGIN
125 %token  K_CONSTANT
126 %token  K_DEBUG
127 %token  K_DECLARE
128 %token  K_DEFAULT
129 %token  K_DOTDOT
130 %token  K_ELSE
131 %token  K_END
132 %token  K_EXCEPTION
133 %token  K_EXIT
134 %token  K_FOR
135 %token  K_FROM
136 %token  K_IF
137 %token  K_IN
138 %token  K_INTO
139 %token  K_LOOP
140 %token  K_NOT
141 %token  K_NOTICE
142 %token  K_NULL
143 %token  K_PERFORM
144 %token  K_RAISE
145 %token  K_RECORD
146 %token  K_RENAME
147 %token  K_RETURN
148 %token  K_REVERSE
149 %token  K_SELECT
150 %token  K_THEN
151 %token  K_TO
152 %token  K_TYPE
153 %token  K_WHEN
154 %token  K_WHILE
155
156         /*
157          * Other tokens
158          */
159 %token  T_FUNCTION
160 %token  T_TRIGGER
161 %token  T_CHAR
162 %token  T_BPCHAR
163 %token  T_VARCHAR
164 %token  T_LABEL
165 %token  T_STRING
166 %token  T_VARIABLE
167 %token  T_ROW
168 %token  T_ROWTYPE
169 %token  T_RECORD
170 %token  T_RECFIELD
171 %token  T_TGARGV
172 %token  T_DTYPE
173 %token  T_WORD
174 %token  T_NUMBER
175 %token  T_ERROR
176
177 %token  O_OPTION
178 %token  O_DUMP
179
180 %%
181
182 pl_function     : T_FUNCTION comp_optsect pl_block
183                     {
184                         yylval.program = (PLpgSQL_stmt_block *)$3;
185                     }
186                 | T_TRIGGER comp_optsect pl_block
187                     {
188                         yylval.program = (PLpgSQL_stmt_block *)$3;
189                     }
190                 ;
191
192 comp_optsect    :
193                 | comp_options
194                 ;
195
196 comp_options    : comp_options comp_option
197                 | comp_option
198                 ;
199
200 comp_option     : O_OPTION O_DUMP
201                     {
202                         plpgsql_DumpExecTree = 1;
203                     }
204                 ;
205
206 pl_block        : decl_sect K_BEGIN lno proc_sect K_END ';'
207                     {
208                         PLpgSQL_stmt_block *new;
209
210                         new = malloc(sizeof(PLpgSQL_stmt_block));
211                         memset(new, 0, sizeof(PLpgSQL_stmt_block));
212
213                         new->cmd_type   = PLPGSQL_STMT_BLOCK;
214                         new->lineno     = $3;
215                         new->label      = $1.label;
216                         new->n_initvars = $1.n_initvars;
217                         new->initvarnos = $1.initvarnos;
218                         new->body       = $4;
219
220                         plpgsql_ns_pop();
221
222                         $$ = (PLpgSQL_stmt *)new;
223                     }
224                 ;
225
226
227 decl_sect       : opt_label
228                     {
229                         plpgsql_ns_setlocal(false);
230                         $$.label      = $1;
231                         $$.n_initvars = 0;
232                         $$.initvarnos = NULL;
233                         plpgsql_add_initdatums(NULL);
234                     }
235                 | opt_label decl_start
236                     {
237                         plpgsql_ns_setlocal(false);
238                         $$.label      = $1;
239                         $$.n_initvars = 0;
240                         $$.initvarnos = NULL;
241                         plpgsql_add_initdatums(NULL);
242                     }
243                 | opt_label decl_start decl_stmts
244                     {
245                         plpgsql_ns_setlocal(false);
246                         if ($3 != NULL) {
247                             $$.label = $3;
248                         } else {
249                             $$.label = $1;
250                         }
251                         $$.n_initvars = plpgsql_add_initdatums(&($$.initvarnos));
252                     }
253                 ;
254
255 decl_start      : K_DECLARE
256                     {
257                         plpgsql_ns_setlocal(true);
258                     }
259                 ;
260
261 decl_stmts      : decl_stmts decl_stmt
262                     {
263                         $$ = $2;
264                     }
265                 | decl_stmt
266                     {
267                         $$ = $1;
268                     }
269                 ;
270
271 decl_stmt       : '<' '<' opt_lblname '>' '>'
272                     {
273                         $$ = $3;
274                     }
275                 | K_DECLARE
276                     {
277                         $$ = NULL;
278                     }
279                 | decl_statement
280                     {
281                         $$ = NULL;
282                     }
283                 ;
284
285 decl_statement  : decl_varname decl_const decl_datatype decl_notnull decl_defval
286                     {
287                         PLpgSQL_var     *new;
288
289                         new = malloc(sizeof(PLpgSQL_var));
290
291                         new->dtype      = PLPGSQL_DTYPE_VAR;
292                         new->refname    = $1.name;
293                         new->lineno     = $1.lineno;
294
295                         new->datatype   = $3;
296                         new->isconst    = $2;
297                         new->notnull    = $4;
298                         new->default_val = $5;
299
300                         plpgsql_adddatum((PLpgSQL_datum *)new);
301                         plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
302                                                 $1.name);
303                     }
304                 | decl_varname K_RECORD ';'
305                     {
306                         PLpgSQL_rec     *new;
307
308                         new = malloc(sizeof(PLpgSQL_var));
309
310                         new->dtype      = PLPGSQL_DTYPE_REC;
311                         new->refname    = $1.name;
312                         new->lineno     = $1.lineno;
313
314                         plpgsql_adddatum((PLpgSQL_datum *)new);
315                         plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, new->recno,
316                                                 $1.name);
317                     }
318                 | decl_varname decl_rowtype ';'
319                     {
320                         $2->dtype       = PLPGSQL_DTYPE_ROW;
321                         $2->refname     = $1.name;
322                         $2->lineno      = $1.lineno;
323
324                         plpgsql_adddatum((PLpgSQL_datum *)$2);
325                         plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, $2->rowno,
326                                                 $1.name);
327                     }
328                 | decl_varname K_ALIAS K_FOR decl_aliasitem ';'
329                     {
330                         plpgsql_ns_additem($4->itemtype,
331                                         $4->itemno, $1.name);
332                     }
333                 | K_RENAME decl_renname K_TO decl_renname ';'
334                     {
335                         plpgsql_ns_rename($2, $4);
336                     }
337                 ;
338
339 decl_aliasitem  : T_WORD
340                     {
341                         PLpgSQL_nsitem *nsi;
342                         char    *name;
343
344                         plpgsql_ns_setlocal(false);
345                         name = plpgsql_tolower(yytext);
346                         if (name[0] != '$') {
347                             elog(ERROR, "can only alias positional parameters");
348                         }
349                         nsi = plpgsql_ns_lookup(name, NULL);
350                         if (nsi == NULL) {
351                             elog(ERROR, "function has no parameter %s", name);
352                         }
353
354                         plpgsql_ns_setlocal(true);
355
356                         $$ = nsi;
357                     }
358                 ;
359
360 decl_rowtype    : T_ROW
361                     {
362                         $$ = yylval.row;
363                     }
364                 ;
365
366 decl_varname    : T_WORD
367                     {
368                         $$.name = strdup(yytext);
369                         $$.lineno  = yylineno;
370                     }
371                 ;
372
373 decl_renname    : T_WORD
374                     {
375                         $$ = plpgsql_tolower(yytext);
376                     }
377                 ;
378
379 decl_const      :
380                     { $$ = 0; }
381                 | K_CONSTANT
382                     { $$ = 1; }
383                 ;
384
385 decl_datatype   : decl_dtypename
386                     {
387                         $$ = $1;
388                     }
389                 ;
390
391 decl_dtypename  : T_DTYPE
392                     {
393                         $$ = yylval.dtype;
394                     }
395                 | T_CHAR decl_atttypmod
396                     {
397                         if ($2 < 0) {
398                             plpgsql_parse_word("char");
399                             $$ = yylval.dtype;
400                         } else {
401                             plpgsql_parse_word("bpchar");
402                             $$ = yylval.dtype;
403                             $$->atttypmod = $2;
404                         }
405                     }
406                 | T_VARCHAR decl_atttypmod
407                     {
408                         plpgsql_parse_word("varchar");
409                         $$ = yylval.dtype;
410                         $$->atttypmod = $2;
411                     }
412                 | T_BPCHAR '(' decl_atttypmodval ')'
413                     {
414                         plpgsql_parse_word("bpchar");
415                         $$ = yylval.dtype;
416                         $$->atttypmod = $3;
417                     }
418                 ;
419
420 decl_atttypmod  :
421                     {
422                         $$ = -1;
423                     }
424                 | '(' decl_atttypmodval ')'
425                     {
426                         $$ = $2;
427                     }
428                 ;
429
430 decl_atttypmodval       : T_NUMBER
431                     {
432                         $$ = int2in(yytext) + VARHDRSZ;
433                     }
434                 ;
435
436 decl_notnull    :
437                     { $$ = 0; }
438                 | K_NOT K_NULL
439                     { $$ = 1; }
440                 ;
441
442 decl_defval     : ';'
443                     { $$ = NULL; }
444                 | decl_defkey
445                     {
446                         int             tok;
447                         int             lno;
448                         PLpgSQL_dstring ds;
449                         PLpgSQL_expr    *expr;
450
451                         lno = yylineno;
452                         expr = malloc(sizeof(PLpgSQL_expr));
453                         plpgsql_dstring_init(&ds);
454                         plpgsql_dstring_append(&ds, "SELECT ");
455
456                         expr->dtype   = PLPGSQL_DTYPE_EXPR;
457                         expr->plan    = NULL;
458                         expr->nparams = 0;
459
460                         tok = yylex();
461                         switch (tok) {
462                             case 0:
463                                 plpgsql_error_lineno = lno;
464                                 plpgsql_comperrinfo();
465                                 elog(ERROR, "unexpected end of file");
466                             case K_NULL:
467                                 if (yylex() != ';') {
468                                     plpgsql_error_lineno = lno;
469                                     plpgsql_comperrinfo();
470                                     elog(ERROR, "expectec ; after NULL");
471                                 }
472                                 free(expr);
473                                 plpgsql_dstring_free(&ds);
474
475                                 $$ = NULL;
476                                 break;
477
478                             default:
479                                 plpgsql_dstring_append(&ds, yytext);
480                                 while ((tok = yylex()) != ';') {
481                                     if (tok == 0) {
482                                         plpgsql_error_lineno = lno;
483                                         plpgsql_comperrinfo();
484                                         elog(ERROR, "unterminated default value");
485                                     }
486                                     if (plpgsql_SpaceScanned) {
487                                         plpgsql_dstring_append(&ds, " ");
488                                     }
489                                     plpgsql_dstring_append(&ds, yytext);
490                                 }
491                                 expr->query = strdup(plpgsql_dstring_get(&ds));
492                                 plpgsql_dstring_free(&ds);
493
494                                 $$ = expr;
495                                 break;
496                         }
497                     }
498                 ;
499
500 decl_defkey     : K_ASSIGN
501                 | K_DEFAULT
502
503 proc_sect       :
504                         {
505                                 PLpgSQL_stmts   *new;
506
507                                 new = malloc(sizeof(PLpgSQL_stmts));
508                                 memset(new, 0, sizeof(PLpgSQL_stmts));
509                                 $$ = new;
510                         }
511                 | proc_stmts
512                         {
513                                 $$ = $1;
514                         }
515                 ;
516
517 proc_stmts      : proc_stmts proc_stmt
518                         {
519                                 if ($1->stmts_used == $1->stmts_alloc) {
520                                     $1->stmts_alloc *= 2;
521                                     $1->stmts = realloc($1->stmts, sizeof(PLpgSQL_stmt *) * $1->stmts_alloc);
522                                 }
523                                 $1->stmts[$1->stmts_used++] = (struct PLpgSQL_stmt *)$2;
524
525                                 $$ = $1;
526                         }
527                 | proc_stmt
528                         {
529                                 PLpgSQL_stmts   *new;
530
531                                 new = malloc(sizeof(PLpgSQL_stmts));
532                                 memset(new, 0, sizeof(PLpgSQL_stmts));
533
534                                 new->stmts_alloc = 64;
535                                 new->stmts_used  = 1;
536                                 new->stmts = malloc(sizeof(PLpgSQL_stmt *) * new->stmts_alloc);
537                                 new->stmts[0] = (struct PLpgSQL_stmt *)$1;
538
539                                 $$ = new;
540                         }
541                 ;
542
543 proc_stmt       : pl_block
544                         { $$ = $1; }
545                 | stmt_assign
546                         { $$ = $1; }
547                 | stmt_if
548                         { $$ = $1; }
549                 | stmt_loop
550                         { $$ = $1; }
551                 | stmt_while
552                         { $$ = $1; }
553                 | stmt_fori
554                         { $$ = $1; }
555                 | stmt_fors
556                         { $$ = $1; }
557                 | stmt_select
558                         { $$ = $1; }
559                 | stmt_exit
560                         { $$ = $1; }
561                 | stmt_return
562                         { $$ = $1; }
563                 | stmt_raise
564                         { $$ = $1; }
565                 | stmt_execsql
566                         { $$ = $1; }
567                 | stmt_perform
568                         { $$ = $1; }
569                 ;
570
571 stmt_perform    : K_PERFORM lno expr_until_semi
572                     {
573                         PLpgSQL_stmt_assign *new;
574
575                         new = malloc(sizeof(PLpgSQL_stmt_assign));
576                         memset(new, 0, sizeof(PLpgSQL_stmt_assign));
577
578                         new->cmd_type = PLPGSQL_STMT_ASSIGN;
579                         new->lineno   = $2;
580                         new->varno = -1;
581                         new->expr  = $3;
582
583                         $$ = (PLpgSQL_stmt *)new;
584                     }
585                 ;
586
587 stmt_assign     : assign_var lno K_ASSIGN expr_until_semi
588                     {
589                         PLpgSQL_stmt_assign *new;
590
591                         new = malloc(sizeof(PLpgSQL_stmt_assign));
592                         memset(new, 0, sizeof(PLpgSQL_stmt_assign));
593
594                         new->cmd_type = PLPGSQL_STMT_ASSIGN;
595                         new->lineno   = $2;
596                         new->varno = $1;
597                         new->expr  = $4;
598
599                         $$ = (PLpgSQL_stmt *)new;
600                     }
601                 ;
602
603 assign_var      : T_VARIABLE
604                     {
605                         if (yylval.var->isconst) {
606                             plpgsql_comperrinfo();
607                             elog(ERROR, "%s is declared CONSTANT", yylval.var->refname);
608                         }
609                         $$ = yylval.var->varno;
610                     }
611                 | T_RECFIELD
612                     {
613                         $$ = yylval.recfield->rfno;
614                     }
615                 ;
616
617 stmt_if         : K_IF lno expr_until_then proc_sect stmt_else K_END K_IF ';'
618                     {
619                         PLpgSQL_stmt_if *new;
620
621                         new = malloc(sizeof(PLpgSQL_stmt_if));
622                         memset(new, 0, sizeof(PLpgSQL_stmt_if));
623
624                         new->cmd_type   = PLPGSQL_STMT_IF;
625                         new->lineno     = $2;
626                         new->cond       = $3;
627                         new->true_body  = $4;
628                         new->false_body = $5;
629
630                         $$ = (PLpgSQL_stmt *)new;
631                     }
632                 ;
633
634 stmt_else       :
635                         {
636                                 PLpgSQL_stmts   *new;
637
638                                 new = malloc(sizeof(PLpgSQL_stmts));
639                                 memset(new, 0, sizeof(PLpgSQL_stmts));
640                                 $$ = new;
641                         }
642                 | K_ELSE proc_sect
643                         { $$ = $2; }
644                 ;
645
646 stmt_loop       : opt_label K_LOOP lno loop_body
647                     {
648                         PLpgSQL_stmt_loop *new;
649
650                         new = malloc(sizeof(PLpgSQL_stmt_loop));
651                         memset(new, 0, sizeof(PLpgSQL_stmt_loop));
652
653                         new->cmd_type = PLPGSQL_STMT_LOOP;
654                         new->lineno   = $3;
655                         new->label    = $1;
656                         new->body     = $4;
657
658                         plpgsql_ns_pop();
659
660                         $$ = (PLpgSQL_stmt *)new;
661                     }
662                 ;
663
664 stmt_while      : opt_label K_WHILE lno expr_until_loop loop_body
665                     {
666                         PLpgSQL_stmt_while *new;
667
668                         new = malloc(sizeof(PLpgSQL_stmt_while));
669                         memset(new, 0, sizeof(PLpgSQL_stmt_while));
670
671                         new->cmd_type = PLPGSQL_STMT_WHILE;
672                         new->lineno   = $3;
673                         new->label    = $1;
674                         new->cond     = $4;
675                         new->body     = $5;
676
677                         plpgsql_ns_pop();
678
679                         $$ = (PLpgSQL_stmt *)new;
680                     }
681                 ;
682
683 stmt_fori       : opt_label K_FOR lno fori_var K_IN fori_lower expr_until_loop loop_body
684                     {
685                         PLpgSQL_stmt_fori       *new;
686
687                         new = malloc(sizeof(PLpgSQL_stmt_fori));
688                         memset(new, 0, sizeof(PLpgSQL_stmt_fori));
689
690                         new->cmd_type = PLPGSQL_STMT_FORI;
691                         new->lineno   = $3;
692                         new->label    = $1;
693                         new->var      = $4;
694                         new->reverse  = $6.reverse;
695                         new->lower    = $6.expr;
696                         new->upper    = $7;
697                         new->body     = $8;
698
699                         plpgsql_ns_pop();
700
701                         $$ = (PLpgSQL_stmt *)new;
702                     }
703                 ;
704
705 fori_var        : fori_varname
706                     {
707                         PLpgSQL_var     *new;
708
709                         new = malloc(sizeof(PLpgSQL_var));
710
711                         new->dtype      = PLPGSQL_DTYPE_VAR;
712                         new->refname    = $1.name;
713                         new->lineno     = $1.lineno;
714
715                         plpgsql_parse_word("integer");
716
717                         new->datatype   = yylval.dtype;
718                         new->isconst    = false;
719                         new->notnull    = false;
720                         new->default_val = NULL;
721
722                         plpgsql_adddatum((PLpgSQL_datum *)new);
723                         plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
724                                                 $1.name);
725
726                         plpgsql_add_initdatums(NULL);
727
728                         $$ = new;
729                     }
730                 ;
731
732 fori_varname    : T_VARIABLE
733                     {
734                         $$.name = strdup(yytext);
735                         $$.lineno = yylineno;
736                     }
737                 | T_WORD
738                     {
739                         $$.name = strdup(yytext);
740                         $$.lineno = yylineno;
741                     }
742                 ;
743
744 fori_lower      :
745                     {
746                         int                     tok;
747                         int                     lno;
748                         PLpgSQL_dstring ds;
749                         int                     nparams = 0;
750                         int                     params[1024];
751                         char            buf[32];
752                         PLpgSQL_expr    *expr;
753                         int                     firsttok = 1;
754
755                         lno = yylineno;
756                         plpgsql_dstring_init(&ds);
757                         plpgsql_dstring_append(&ds, "SELECT ");
758
759                         $$.reverse = 0;
760                         while((tok = yylex()) != K_DOTDOT) {
761                             if (firsttok) {
762                                 firsttok = 0;
763                                 if (tok == K_REVERSE) {
764                                     $$.reverse = 1;
765                                     continue;
766                                 }
767                             }
768                             if (tok == ';') break;
769                             if (plpgsql_SpaceScanned) {
770                                 plpgsql_dstring_append(&ds, " ");
771                             }
772                             switch (tok) {
773                                 case T_VARIABLE:
774                                     params[nparams] = yylval.var->varno;
775                                     sprintf(buf, "$%d", ++nparams);
776                                     plpgsql_dstring_append(&ds, buf);
777                                     break;
778                                     
779                                 case T_RECFIELD:
780                                     params[nparams] = yylval.recfield->rfno;
781                                     sprintf(buf, "$%d", ++nparams);
782                                     plpgsql_dstring_append(&ds, buf);
783                                     break;
784                                     
785                                 case T_TGARGV:
786                                     params[nparams] = yylval.trigarg->dno;
787                                     sprintf(buf, "$%d", ++nparams);
788                                     plpgsql_dstring_append(&ds, buf);
789                                     break;
790                                     
791                                 default:
792                                     if (tok == 0) {
793                                         plpgsql_error_lineno = lno;
794                                         plpgsql_comperrinfo();
795                                         elog(ERROR, "missing .. to terminate lower bound of for loop");
796                                     }
797                                     plpgsql_dstring_append(&ds, yytext);
798                                     break;
799                             }
800                         }
801
802                         expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
803                         expr->dtype             = PLPGSQL_DTYPE_EXPR;
804                         expr->query             = strdup(plpgsql_dstring_get(&ds));
805                         expr->plan              = NULL;
806                         expr->nparams   = nparams;
807                         while(nparams-- > 0) {
808                             expr->params[nparams] = params[nparams];
809                         }
810                         plpgsql_dstring_free(&ds);
811                         $$.expr = expr;
812                     }
813
814 stmt_fors       : opt_label K_FOR lno fors_target K_IN K_SELECT expr_until_loop loop_body
815                     {
816                         PLpgSQL_stmt_fors       *new;
817
818                         new = malloc(sizeof(PLpgSQL_stmt_fors));
819                         memset(new, 0, sizeof(PLpgSQL_stmt_fors));
820
821                         new->cmd_type = PLPGSQL_STMT_FORS;
822                         new->lineno   = $3;
823                         new->label    = $1;
824                         switch ($4->dtype) {
825                             case PLPGSQL_DTYPE_REC:
826                                 new->rec = $4;
827                                 break;
828                             case PLPGSQL_DTYPE_ROW:
829                                 new->row = (PLpgSQL_row *)$4;
830                                 break;
831                             default:
832                                 plpgsql_comperrinfo();
833                                 elog(ERROR, "unknown dtype %d in stmt_fors", $4->dtype);
834                         }
835                         new->query = $7;
836                         new->body  = $8;
837
838                         plpgsql_ns_pop();
839
840                         $$ = (PLpgSQL_stmt *)new;
841                     }
842
843 fors_target     : T_RECORD
844                     {
845                         $$ = yylval.rec;
846                     }
847                 | T_ROW
848                     {
849                         $$ = (PLpgSQL_rec *)(yylval.row);
850                     }
851                 ;
852
853 stmt_select     : K_SELECT lno
854                     {
855                         $$ = make_select_stmt();
856                         $$->lineno = $2;
857                     }
858                 ;
859
860 stmt_exit       : K_EXIT lno opt_exitlabel opt_exitcond
861                     {
862                         PLpgSQL_stmt_exit *new;
863
864                         new = malloc(sizeof(PLpgSQL_stmt_exit));
865                         memset(new, 0, sizeof(PLpgSQL_stmt_exit));
866
867                         new->cmd_type = PLPGSQL_STMT_EXIT;
868                         new->lineno   = $2;
869                         new->label    = $3;
870                         new->cond     = $4;
871
872                         $$ = (PLpgSQL_stmt *)new;
873                     }
874                 ;
875
876 stmt_return     : K_RETURN lno
877                     {
878                         PLpgSQL_stmt_return *new;
879                         PLpgSQL_expr    *expr = NULL;
880                         int             tok;
881
882                         new = malloc(sizeof(PLpgSQL_stmt_return));
883                         memset(new, 0, sizeof(PLpgSQL_stmt_return));
884
885                         if (plpgsql_curr_compile->fn_retistuple) {
886                             new->retistuple = true;
887                             new->retrecno   = -1;
888                             switch (tok = yylex()) {
889                                 case K_NULL:
890                                     expr = NULL;
891                                     break;
892
893                                 case T_ROW:
894                                     expr = make_tupret_expr(yylval.row);
895                                     break;
896
897                                 case T_RECORD:
898                                     new->retrecno = yylval.rec->recno;
899                                     expr = NULL;
900                                     break;
901
902                                 default:
903                                     yyerror("return type mismatch in function returning table row");
904                                     break;
905                             }
906                             if (yylex() != ';') {
907                                 yyerror("expected ';'");
908                             }
909                         } else {
910                             new->retistuple = false;
911                             expr = plpgsql_read_expression(';', ";");
912                         }
913
914                         new->cmd_type = PLPGSQL_STMT_RETURN;
915                         new->lineno   = $2;
916                         new->expr     = expr;
917
918                         $$ = (PLpgSQL_stmt *)new;
919                     }
920                 ;
921
922 stmt_raise      : K_RAISE lno raise_level raise_msg raise_params ';'
923                     {
924                         PLpgSQL_stmt_raise      *new;
925
926                         new = malloc(sizeof(PLpgSQL_stmt_raise));
927
928                         new->cmd_type   = PLPGSQL_STMT_RAISE;
929                         new->lineno     = $2;
930                         new->elog_level = $3;
931                         new->message    = $4;
932                         new->nparams    = $5.nused;
933                         new->params     = malloc(sizeof(int) * $5.nused);
934                         memcpy(new->params, $5.dtnums, sizeof(int) * $5.nused);
935
936                         $$ = (PLpgSQL_stmt *)new;
937                     }
938                 | K_RAISE lno raise_level raise_msg ';'
939                     {
940                         PLpgSQL_stmt_raise      *new;
941
942                         new = malloc(sizeof(PLpgSQL_stmt_raise));
943
944                         new->cmd_type   = PLPGSQL_STMT_RAISE;
945                         new->lineno     = $2;
946                         new->elog_level = $3;
947                         new->message    = $4;
948                         new->nparams    = 0;
949                         new->params     = NULL;
950
951                         $$ = (PLpgSQL_stmt *)new;
952                     }
953                 ;
954
955 raise_msg       : T_STRING
956                     {
957                         $$ = strdup(yytext);
958                     }
959                 ;
960
961 raise_level     : K_EXCEPTION
962                     {
963                         $$ = ERROR;
964                     }
965                 | K_NOTICE
966                     {
967                         $$ = NOTICE;
968                     }
969                 | K_DEBUG
970                     {
971                         $$ = DEBUG;
972                     }
973                 ;
974
975 raise_params    : raise_params raise_param
976                     {
977                         if ($1.nused == $1.nalloc) {
978                             $1.nalloc *= 2;
979                             $1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc);
980                         }
981                         $1.dtnums[$1.nused++] = $2;
982
983                         $$.nalloc = $1.nalloc;
984                         $$.nused  = $1.nused;
985                         $$.dtnums = $1.dtnums;
986                     }
987                 | raise_param
988                     {
989                         $$.nalloc = 1;
990                         $$.nused  = 1;
991                         $$.dtnums = palloc(sizeof(int) * $$.nalloc);
992                         $$.dtnums[0] = $1;
993                     }
994                 ;
995
996 raise_param     : ',' T_VARIABLE
997                     {
998                         $$ = yylval.var->varno;
999                     }
1000                 | ',' T_RECFIELD
1001                     {
1002                         $$ = yylval.recfield->rfno;
1003                     }
1004                 | ',' T_TGARGV
1005                     {
1006                         $$ = yylval.trigarg->dno;
1007                     }
1008                 ;
1009
1010 loop_body       : proc_sect K_END K_LOOP ';'
1011                     { $$ = $1; }
1012                 ;
1013
1014 stmt_execsql    : execsql_start lno
1015                     {
1016                         PLpgSQL_stmt_execsql    *new;
1017
1018                         new = malloc(sizeof(PLpgSQL_stmt_execsql));
1019                         new->cmd_type = PLPGSQL_STMT_EXECSQL;
1020                         new->lineno   = $2;
1021                         new->sqlstmt  = read_sqlstmt(';', ";", $1);
1022
1023                         $$ = (PLpgSQL_stmt *)new;
1024                     }
1025                 ;
1026
1027 execsql_start   : T_WORD
1028                     { $$ = strdup(yytext); }
1029                 | T_ERROR
1030                     { $$ = strdup(yytext); }
1031                 ;
1032
1033 expr_until_semi :
1034                     { $$ = plpgsql_read_expression(';', ";"); }
1035                 ;
1036
1037 expr_until_then :
1038                     { $$ = plpgsql_read_expression(K_THEN, "THEN"); }
1039                 ;
1040
1041 expr_until_loop :
1042                     { $$ = plpgsql_read_expression(K_LOOP, "LOOP"); }
1043                 ;
1044
1045 opt_label       :
1046                     {
1047                         plpgsql_ns_push(NULL);
1048                         $$ = NULL;
1049                     }
1050                 | '<' '<' opt_lblname '>' '>'
1051                     {
1052                         plpgsql_ns_push($3);
1053                         $$ = $3;
1054                     }
1055                 ;
1056
1057 opt_exitlabel   :
1058                     { $$ = NULL; }
1059                 | T_LABEL
1060                     { $$ = strdup(yytext); }
1061                 ;
1062
1063 opt_exitcond    : ';'
1064                     { $$ = NULL; }
1065                 | K_WHEN expr_until_semi
1066                     { $$ = $2; }
1067                 ;
1068
1069 opt_lblname     : T_WORD
1070                     { $$ = strdup(yytext); }
1071                 ;
1072
1073 lno             :
1074                     {
1075                         plpgsql_error_lineno = yylineno;
1076                         $$ = yylineno;
1077                     }
1078                 ;
1079
1080 %%
1081
1082 #include "pl_scan.c"
1083
1084 PLpgSQL_expr *
1085 plpgsql_read_expression (int until, char *s)
1086 {
1087     return read_sqlstmt(until, s, "SELECT ");
1088 }
1089
1090
1091 static PLpgSQL_expr *
1092 read_sqlstmt (int until, char *s, char *sqlstart)
1093 {
1094     int                 tok;
1095     int                 lno;
1096     PLpgSQL_dstring     ds;
1097     int                 nparams = 0;
1098     int                 params[1024];
1099     char                buf[32];
1100     PLpgSQL_expr        *expr;
1101
1102     lno = yylineno;
1103     plpgsql_dstring_init(&ds);
1104     plpgsql_dstring_append(&ds, sqlstart);
1105
1106     while((tok = yylex()) != until) {
1107         if (tok == ';') break;
1108         if (plpgsql_SpaceScanned) {
1109             plpgsql_dstring_append(&ds, " ");
1110         }
1111         switch (tok) {
1112             case T_VARIABLE:
1113                 params[nparams] = yylval.var->varno;
1114                 sprintf(buf, "$%d", ++nparams);
1115                 plpgsql_dstring_append(&ds, buf);
1116                 break;
1117                 
1118             case T_RECFIELD:
1119                 params[nparams] = yylval.recfield->rfno;
1120                 sprintf(buf, "$%d", ++nparams);
1121                 plpgsql_dstring_append(&ds, buf);
1122                 break;
1123                 
1124             case T_TGARGV:
1125                 params[nparams] = yylval.trigarg->dno;
1126                 sprintf(buf, "$%d", ++nparams);
1127                 plpgsql_dstring_append(&ds, buf);
1128                 break;
1129                 
1130             default:
1131                 if (tok == 0) {
1132                     plpgsql_error_lineno = lno;
1133                     plpgsql_comperrinfo();
1134                     elog(ERROR, "missing %s at end of SQL statement", s);
1135                 }
1136                 plpgsql_dstring_append(&ds, yytext);
1137                 break;
1138         }
1139     }
1140
1141     expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
1142     expr->dtype         = PLPGSQL_DTYPE_EXPR;
1143     expr->query         = strdup(plpgsql_dstring_get(&ds));
1144     expr->plan          = NULL;
1145     expr->nparams       = nparams;
1146     while(nparams-- > 0) {
1147         expr->params[nparams] = params[nparams];
1148     }
1149     plpgsql_dstring_free(&ds);
1150     
1151     return expr;
1152 }
1153
1154
1155 static PLpgSQL_stmt *
1156 make_select_stmt()
1157 {
1158     int                 tok;
1159     int                 lno;
1160     PLpgSQL_dstring     ds;
1161     int                 nparams = 0;
1162     int                 params[1024];
1163     char                buf[32];
1164     PLpgSQL_expr        *expr;
1165     PLpgSQL_row         *row = NULL;
1166     PLpgSQL_rec         *rec = NULL;
1167     PLpgSQL_stmt_select *select;
1168     int                 have_nexttok = 0;
1169
1170     lno = yylineno;
1171     plpgsql_dstring_init(&ds);
1172     plpgsql_dstring_append(&ds, "SELECT ");
1173
1174     while((tok = yylex()) != K_INTO) {
1175         if (tok == ';') {
1176             PLpgSQL_stmt_execsql        *execsql;
1177
1178             expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
1179             expr->dtype         = PLPGSQL_DTYPE_EXPR;
1180             expr->query         = strdup(plpgsql_dstring_get(&ds));
1181             expr->plan          = NULL;
1182             expr->nparams       = nparams;
1183             while(nparams-- > 0) {
1184                 expr->params[nparams] = params[nparams];
1185             }
1186             plpgsql_dstring_free(&ds);
1187
1188             execsql = malloc(sizeof(PLpgSQL_stmt_execsql));
1189             execsql->cmd_type = PLPGSQL_STMT_EXECSQL;
1190             execsql->sqlstmt  = expr;
1191
1192             return (PLpgSQL_stmt *)execsql;
1193         }
1194
1195         if (plpgsql_SpaceScanned) {
1196             plpgsql_dstring_append(&ds, " ");
1197         }
1198         switch (tok) {
1199             case T_VARIABLE:
1200                 params[nparams] = yylval.var->varno;
1201                 sprintf(buf, "$%d", ++nparams);
1202                 plpgsql_dstring_append(&ds, buf);
1203                 break;
1204                 
1205             case T_RECFIELD:
1206                 params[nparams] = yylval.recfield->rfno;
1207                 sprintf(buf, "$%d", ++nparams);
1208                 plpgsql_dstring_append(&ds, buf);
1209                 break;
1210                 
1211             case T_TGARGV:
1212                 params[nparams] = yylval.trigarg->dno;
1213                 sprintf(buf, "$%d", ++nparams);
1214                 plpgsql_dstring_append(&ds, buf);
1215                 break;
1216                 
1217             default:
1218                 if (tok == 0) {
1219                     plpgsql_error_lineno = yylineno;
1220                     plpgsql_comperrinfo();
1221                     elog(ERROR, "unexpected end of file");
1222                 }
1223                 plpgsql_dstring_append(&ds, yytext);
1224                 break;
1225         }
1226     }
1227
1228     tok = yylex();
1229     switch (tok) {
1230         case T_ROW:
1231             row = yylval.row;
1232             break;
1233
1234         case T_RECORD:
1235             rec = yylval.rec;
1236             break;
1237
1238         case T_VARIABLE:
1239         case T_RECFIELD:
1240             {
1241                 PLpgSQL_var     *var;
1242                 PLpgSQL_recfield *recfield;
1243                 int             nfields = 1;
1244                 char            *fieldnames[1024];
1245                 int             varnos[1024];
1246
1247                 switch (tok) {
1248                     case T_VARIABLE:
1249                         var = yylval.var;
1250                         fieldnames[0] = strdup(yytext);
1251                         varnos[0]     = var->varno;
1252                         break;
1253                     
1254                     case T_RECFIELD:
1255                         recfield = yylval.recfield;
1256                         fieldnames[0] = strdup(yytext);
1257                         varnos[0]     = recfield->rfno;
1258                         break;
1259                 }
1260
1261                 while ((tok = yylex()) == ',') {
1262                     tok = yylex();
1263                     switch(tok) {
1264                         case T_VARIABLE:
1265                             var = yylval.var;
1266                             fieldnames[nfields] = strdup(yytext);
1267                             varnos[nfields++]   = var->varno;
1268                             break;
1269
1270                         case T_RECFIELD:
1271                             recfield = yylval.recfield;
1272                             fieldnames[0] = strdup(yytext);
1273                             varnos[0]     = recfield->rfno;
1274                             break;
1275
1276                         default:
1277                             elog(ERROR, "plpgsql: %s is not a variable or record field", yytext);
1278                     }
1279                 }
1280                 row = malloc(sizeof(PLpgSQL_row));
1281                 row->dtype = PLPGSQL_DTYPE_ROW;
1282                 row->refname = strdup("*internal*");
1283                 row->lineno = yylineno;
1284                 row->rowtypeclass = InvalidOid;
1285                 row->nfields = nfields;
1286                 row->fieldnames = malloc(sizeof(char *) * nfields);
1287                 row->varnos = malloc(sizeof(int) * nfields);
1288                 while (--nfields >= 0) {
1289                     row->fieldnames[nfields] = fieldnames[nfields];
1290                     row->varnos[nfields] = varnos[nfields];
1291                 }
1292
1293                 plpgsql_adddatum((PLpgSQL_datum *)row);
1294
1295                 have_nexttok = 1;
1296             }
1297             break;
1298
1299         default:
1300             {
1301                 if (plpgsql_SpaceScanned) {
1302                     plpgsql_dstring_append(&ds, " ");
1303                 }
1304                 plpgsql_dstring_append(&ds, yytext);
1305
1306                 while(1) {
1307                     tok = yylex();
1308                     if (tok == ';') {
1309                         PLpgSQL_stmt_execsql    *execsql;
1310
1311                         expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
1312                         expr->dtype             = PLPGSQL_DTYPE_EXPR;
1313                         expr->query             = strdup(plpgsql_dstring_get(&ds));
1314                         expr->plan              = NULL;
1315                         expr->nparams   = nparams;
1316                         while(nparams-- > 0) {
1317                             expr->params[nparams] = params[nparams];
1318                         }
1319                         plpgsql_dstring_free(&ds);
1320
1321                         execsql = malloc(sizeof(PLpgSQL_stmt_execsql));
1322                         execsql->cmd_type = PLPGSQL_STMT_EXECSQL;
1323                         execsql->sqlstmt  = expr;
1324
1325                         return (PLpgSQL_stmt *)execsql;
1326                     }
1327
1328                     if (plpgsql_SpaceScanned) {
1329                         plpgsql_dstring_append(&ds, " ");
1330                     }
1331                     switch (tok) {
1332                         case T_VARIABLE:
1333                             params[nparams] = yylval.var->varno;
1334                             sprintf(buf, "$%d", ++nparams);
1335                             plpgsql_dstring_append(&ds, buf);
1336                             break;
1337                             
1338                         case T_RECFIELD:
1339                             params[nparams] = yylval.recfield->rfno;
1340                             sprintf(buf, "$%d", ++nparams);
1341                             plpgsql_dstring_append(&ds, buf);
1342                             break;
1343                             
1344                         case T_TGARGV:
1345                             params[nparams] = yylval.trigarg->dno;
1346                             sprintf(buf, "$%d", ++nparams);
1347                             plpgsql_dstring_append(&ds, buf);
1348                             break;
1349                             
1350                         default:
1351                             if (tok == 0) {
1352                                 plpgsql_error_lineno = yylineno;
1353                                 plpgsql_comperrinfo();
1354                                 elog(ERROR, "unexpected end of file");
1355                             }
1356                             plpgsql_dstring_append(&ds, yytext);
1357                             break;
1358                     }
1359                 }
1360             }
1361     }
1362
1363     /************************************************************
1364      * Eat up the rest of the statement after the target fields
1365      ************************************************************/
1366     while(1) {
1367         if (!have_nexttok) {
1368             tok = yylex();
1369         }
1370         have_nexttok = 0;
1371         if (tok == ';') {
1372             break;
1373         }
1374
1375         if (plpgsql_SpaceScanned) {
1376             plpgsql_dstring_append(&ds, " ");
1377         }
1378         switch (tok) {
1379             case T_VARIABLE:
1380                 params[nparams] = yylval.var->varno;
1381                 sprintf(buf, "$%d", ++nparams);
1382                 plpgsql_dstring_append(&ds, buf);
1383                 break;
1384                 
1385             case T_RECFIELD:
1386                 params[nparams] = yylval.recfield->rfno;
1387                 sprintf(buf, "$%d", ++nparams);
1388                 plpgsql_dstring_append(&ds, buf);
1389                 break;
1390                 
1391             case T_TGARGV:
1392                 params[nparams] = yylval.trigarg->dno;
1393                 sprintf(buf, "$%d", ++nparams);
1394                 plpgsql_dstring_append(&ds, buf);
1395                 break;
1396                 
1397             default:
1398                 if (tok == 0) {
1399                     plpgsql_error_lineno = yylineno;
1400                     plpgsql_comperrinfo();
1401                     elog(ERROR, "unexpected end of file");
1402                 }
1403                 plpgsql_dstring_append(&ds, yytext);
1404                 break;
1405         }
1406     }
1407
1408     expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * (nparams - 1));
1409     expr->dtype         = PLPGSQL_DTYPE_EXPR;
1410     expr->query         = strdup(plpgsql_dstring_get(&ds));
1411     expr->plan          = NULL;
1412     expr->nparams       = nparams;
1413     while(nparams-- > 0) {
1414         expr->params[nparams] = params[nparams];
1415     }
1416     plpgsql_dstring_free(&ds);
1417
1418     select = malloc(sizeof(PLpgSQL_stmt_select));
1419     memset(select, 0, sizeof(PLpgSQL_stmt_select));
1420     select->cmd_type = PLPGSQL_STMT_SELECT;
1421     select->rec      = rec;
1422     select->row      = row;
1423     select->query    = expr;
1424     
1425     return (PLpgSQL_stmt *)select;
1426 }
1427
1428
1429 static PLpgSQL_expr *
1430 make_tupret_expr(PLpgSQL_row *row)
1431 {
1432     PLpgSQL_dstring     ds;
1433     PLpgSQL_expr        *expr;
1434     int                 i;
1435     char                buf[16];
1436
1437     expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * (row->nfields - 1));
1438     expr->dtype         = PLPGSQL_DTYPE_EXPR;
1439
1440     plpgsql_dstring_init(&ds);
1441     plpgsql_dstring_append(&ds, "SELECT ");
1442
1443     for (i = 0; i < row->nfields; i++) {
1444         sprintf(buf, "%s$%d", (i > 0) ? "," : "", i + 1);
1445         plpgsql_dstring_append(&ds, buf);
1446         expr->params[i] = row->varnos[i];
1447     }
1448
1449     expr->query         = strdup(plpgsql_dstring_get(&ds));
1450     expr->plan          = NULL;
1451     expr->plan_argtypes = NULL;
1452     expr->nparams       = row->nfields;
1453
1454     plpgsql_dstring_free(&ds);
1455     return expr;
1456 }