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