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