OSDN Git Service

Convert to standard 4-space tabs.
authorBruce Momjian <bruce@momjian.us>
Sat, 10 Feb 2001 22:42:01 +0000 (22:42 +0000)
committerBruce Momjian <bruce@momjian.us>
Sat, 10 Feb 2001 22:42:01 +0000 (22:42 +0000)
src/pl/plpgsql/src/gram.y

index ed17042..80580de 100644 (file)
@@ -1,38 +1,38 @@
 %{
 /**********************************************************************
- * gram.y              - Parser for the PL/pgSQL
- *                       procedural language
+ * gram.y                              - Parser for the PL/pgSQL
+ *                                               procedural language
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.13 2001/01/06 01:39:01 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.14 2001/02/10 22:42:01 momjian Exp $
  *
- *    This software is copyrighted by Jan Wieck - Hamburg.
+ *       This software is copyrighted by Jan Wieck - Hamburg.
  *
- *    The author hereby grants permission  to  use,  copy,  modify,
- *    distribute,  and  license this software and its documentation
- *    for any purpose, provided that existing copyright notices are
- *    retained  in  all  copies  and  that  this notice is included
- *    verbatim in any distributions. No written agreement, license,
- *    or  royalty  fee  is required for any of the authorized uses.
- *    Modifications to this software may be  copyrighted  by  their
- *    author  and  need  not  follow  the licensing terms described
- *    here, provided that the new terms are  clearly  indicated  on
- *    the first page of each file where they apply.
+ *       The author hereby grants permission  to  use,  copy,  modify,
+ *       distribute,  and      license this software and its documentation
+ *       for any purpose, provided that existing copyright notices are
+ *       retained      in      all  copies  and  that  this notice is included
+ *       verbatim in any distributions. No written agreement, license,
+ *       or  royalty  fee      is required for any of the authorized uses.
+ *       Modifications to this software may be  copyrighted  by  their
+ *       author  and  need  not  follow  the licensing terms described
+ *       here, provided that the new terms are  clearly  indicated  on
+ *       the first page of each file where they apply.
  *
- *    IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY
- *    PARTY  FOR  DIRECT,   INDIRECT,   SPECIAL,   INCIDENTAL,   OR
- *    CONSEQUENTIAL   DAMAGES  ARISING  OUT  OF  THE  USE  OF  THIS
- *    SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
- *    IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
- *    DAMAGE.
+ *       IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY
+ *       PARTY  FOR  DIRECT,   INDIRECT,       SPECIAL,   INCIDENTAL,   OR
+ *       CONSEQUENTIAL   DAMAGES  ARISING      OUT  OF  THE  USE  OF  THIS
+ *       SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
+ *       IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ *       DAMAGE.
  *
- *    THE  AUTHOR  AND  DISTRIBUTORS  SPECIFICALLY   DISCLAIM   ANY
- *    WARRANTIES,  INCLUDING,  BUT  NOT  LIMITED  TO,  THE  IMPLIED
- *    WARRANTIES  OF  MERCHANTABILITY,  FITNESS  FOR  A  PARTICULAR
- *    PURPOSE,  AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON
- *    AN "AS IS" BASIS, AND THE AUTHOR  AND  DISTRIBUTORS  HAVE  NO
- *    OBLIGATION   TO   PROVIDE   MAINTENANCE,   SUPPORT,  UPDATES,
- *    ENHANCEMENTS, OR MODIFICATIONS.
+ *       THE  AUTHOR  AND      DISTRIBUTORS  SPECIFICALLY       DISCLAIM       ANY
+ *       WARRANTIES,  INCLUDING,  BUT  NOT  LIMITED  TO,  THE  IMPLIED
+ *       WARRANTIES  OF  MERCHANTABILITY,      FITNESS  FOR  A  PARTICULAR
+ *       PURPOSE,      AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON
+ *       AN "AS IS" BASIS, AND THE AUTHOR      AND  DISTRIBUTORS  HAVE  NO
+ *       OBLIGATION   TO       PROVIDE   MAINTENANCE,   SUPPORT,  UPDATES,
+ *       ENHANCEMENTS, OR MODIFICATIONS.
  *
  **********************************************************************/
 
@@ -52,61 +52,61 @@ static      PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
 %}
 
 %union {
-       int32                   ival;
-       char                    *str;
-       struct {
-           char *name;
-           int  lineno;
-       }                       varname;
-       struct {
-           int  nalloc;
-           int  nused;
-           int  *dtnums;
-       }                       dtlist;
-       struct {
-           int  reverse;
-           PLpgSQL_expr *expr;
-       }                       forilow;
-       struct {
-           char *label;
-           int  n_initvars;
-           int  *initvarnos;
-       }                       declhdr;
-       PLpgSQL_type            *dtype;
-       PLpgSQL_var             *var;
-       PLpgSQL_row             *row;
-       PLpgSQL_rec             *rec;
-       PLpgSQL_recfield        *recfield;
-       PLpgSQL_trigarg         *trigarg;
-       PLpgSQL_expr            *expr;
-       PLpgSQL_stmt            *stmt;
-       PLpgSQL_stmts           *stmts;
-       PLpgSQL_stmt_block      *program;
-       PLpgSQL_nsitem          *nsitem;
+               int32                                   ival;
+               char                                    *str;
+               struct {
+                       char *name;
+                       int  lineno;
+               }                                               varname;
+               struct {
+                       int  nalloc;
+                       int  nused;
+                       int  *dtnums;
+               }                                               dtlist;
+               struct {
+                       int  reverse;
+                       PLpgSQL_expr *expr;
+               }                                               forilow;
+               struct {
+                       char *label;
+                       int  n_initvars;
+                       int  *initvarnos;
+               }                                               declhdr;
+               PLpgSQL_type                    *dtype;
+               PLpgSQL_var                             *var;
+               PLpgSQL_row                             *row;
+               PLpgSQL_rec                             *rec;
+               PLpgSQL_recfield                *recfield;
+               PLpgSQL_trigarg                 *trigarg;
+               PLpgSQL_expr                    *expr;
+               PLpgSQL_stmt                    *stmt;
+               PLpgSQL_stmts                   *stmts;
+               PLpgSQL_stmt_block              *program;
+               PLpgSQL_nsitem                  *nsitem;
 }
 
-%type <declhdr>        decl_sect
-%type <varname>        decl_varname
-%type <str>    decl_renname
+%type <declhdr> decl_sect
+%type <varname> decl_varname
+%type <str>            decl_renname
 %type <ival>   decl_const, decl_notnull, decl_atttypmod, decl_atttypmodval
 %type <expr>   decl_defval
 %type <dtype>  decl_datatype, decl_dtypename
-%type <row>    decl_rowtype
+%type <row>            decl_rowtype
 %type <nsitem> decl_aliasitem
-%type <str>    decl_stmts, decl_stmt
+%type <str>            decl_stmts, decl_stmt
 
 %type <expr>   expr_until_semi, expr_until_then, expr_until_loop
 %type <expr>   opt_exitcond
 
 %type <ival>   assign_var
-%type <var>    fori_var
-%type <varname>        fori_varname
-%type <forilow>        fori_lower
-%type <rec>    fors_target
+%type <var>            fori_var
+%type <varname> fori_varname
+%type <forilow> fori_lower
+%type <rec>            fors_target
 
-%type <str>    opt_lblname, opt_label
-%type <str>    opt_exitlabel
-%type <str>    execsql_start
+%type <str>            opt_lblname, opt_label
+%type <str>            opt_exitlabel
+%type <str>            execsql_start
 
 %type <stmts>  proc_sect, proc_stmts, stmt_else, loop_body
 %type <stmt>   proc_stmt, pl_block
@@ -117,16 +117,16 @@ static    PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
 
 %type <dtlist> raise_params
 %type <ival>   raise_level, raise_param
-%type <str>    raise_msg
+%type <str>            raise_msg
 
 %type <dtlist> getdiag_items, getdiag_targets
 %type <ival>   getdiag_item, getdiag_target
 
 %type <ival>   lno
 
-       /*
-        * Keyword tokens
-        */
+               /*
+                * Keyword tokens
+                */
 %token K_ALIAS
 %token K_ASSIGN
 %token K_BEGIN
@@ -152,7 +152,7 @@ static      PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
 %token K_NOTICE
 %token K_NULL
 %token K_PERFORM
-%token  K_PROCESSED
+%token K_PROCESSED
 %token K_RAISE
 %token K_RECORD
 %token K_RENAME
@@ -166,9 +166,9 @@ static      PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
 %token K_WHEN
 %token K_WHILE
 
-       /*
-        * Other tokens
-        */
+               /*
+                * Other tokens
+                */
 %token T_FUNCTION
 %token T_TRIGGER
 %token T_CHAR
@@ -192,1047 +192,1047 @@ static        PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
 
 %%
 
-pl_function    : T_FUNCTION comp_optsect pl_block
-                   {
-                       yylval.program = (PLpgSQL_stmt_block *)$3;
-                   }
-               | T_TRIGGER comp_optsect pl_block
-                   {
-                       yylval.program = (PLpgSQL_stmt_block *)$3;
-                   }
-               ;
+pl_function            : T_FUNCTION comp_optsect pl_block
+                                       {
+                                               yylval.program = (PLpgSQL_stmt_block *)$3;
+                                       }
+                               | T_TRIGGER comp_optsect pl_block
+                                       {
+                                               yylval.program = (PLpgSQL_stmt_block *)$3;
+                                       }
+                               ;
 
 comp_optsect   :
-               | comp_options
-               ;
+                               | comp_options
+                               ;
 
 comp_options   : comp_options comp_option
-               | comp_option
-               ;
-
-comp_option    : O_OPTION O_DUMP
-                   {
-                       plpgsql_DumpExecTree = 1;
-                   }
-               ;
-
-pl_block       : decl_sect K_BEGIN lno proc_sect K_END ';'
-                   {
-                       PLpgSQL_stmt_block *new;
-
-                       new = malloc(sizeof(PLpgSQL_stmt_block));
-                       memset(new, 0, sizeof(PLpgSQL_stmt_block));
-
-                       new->cmd_type   = PLPGSQL_STMT_BLOCK;
-                       new->lineno     = $3;
-                       new->label      = $1.label;
-                       new->n_initvars = $1.n_initvars;
-                       new->initvarnos = $1.initvarnos;
-                       new->body       = $4;
-
-                       plpgsql_ns_pop();
-
-                       $$ = (PLpgSQL_stmt *)new;
-                   }
-               ;
-
-
-decl_sect      : opt_label
-                   {
-                       plpgsql_ns_setlocal(false);
-                       $$.label      = $1;
-                       $$.n_initvars = 0;
-                       $$.initvarnos = NULL;
-                       plpgsql_add_initdatums(NULL);
-                   }
-               | opt_label decl_start
-                   {
-                       plpgsql_ns_setlocal(false);
-                       $$.label      = $1;
-                       $$.n_initvars = 0;
-                       $$.initvarnos = NULL;
-                       plpgsql_add_initdatums(NULL);
-                   }
-               | opt_label decl_start decl_stmts
-                   {
-                       plpgsql_ns_setlocal(false);
-                       if ($3 != NULL) {
-                           $$.label = $3;
-                       } else {
-                           $$.label = $1;
-                       }
-                       $$.n_initvars = plpgsql_add_initdatums(&($$.initvarnos));
-                   }
-               ;
-
-decl_start     : K_DECLARE
-                   {
-                       plpgsql_ns_setlocal(true);
-                   }
-               ;
-
-decl_stmts     : decl_stmts decl_stmt
-                   {
-                       $$ = $2;
-                   }
-               | decl_stmt
-                   {
-                       $$ = $1;
-                   }
-               ;
-
-decl_stmt      : '<' '<' opt_lblname '>' '>'
-                   {
-                       $$ = $3;
-                   }
-               | K_DECLARE
-                   {
-                       $$ = NULL;
-                   }
-               | decl_statement
-                   {
-                       $$ = NULL;
-                   }
-               ;
+                               | comp_option
+                               ;
+
+comp_option            : O_OPTION O_DUMP
+                                       {
+                                               plpgsql_DumpExecTree = 1;
+                                       }
+                               ;
+
+pl_block               : decl_sect K_BEGIN lno proc_sect K_END ';'
+                                       {
+                                               PLpgSQL_stmt_block *new;
+
+                                               new = malloc(sizeof(PLpgSQL_stmt_block));
+                                               memset(new, 0, sizeof(PLpgSQL_stmt_block));
+
+                                               new->cmd_type   = PLPGSQL_STMT_BLOCK;
+                                               new->lineno             = $3;
+                                               new->label              = $1.label;
+                                               new->n_initvars = $1.n_initvars;
+                                               new->initvarnos = $1.initvarnos;
+                                               new->body               = $4;
+
+                                               plpgsql_ns_pop();
+
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
+                               ;
+
+
+decl_sect              : opt_label
+                                       {
+                                               plpgsql_ns_setlocal(false);
+                                               $$.label          = $1;
+                                               $$.n_initvars = 0;
+                                               $$.initvarnos = NULL;
+                                               plpgsql_add_initdatums(NULL);
+                                       }
+                               | opt_label decl_start
+                                       {
+                                               plpgsql_ns_setlocal(false);
+                                               $$.label          = $1;
+                                               $$.n_initvars = 0;
+                                               $$.initvarnos = NULL;
+                                               plpgsql_add_initdatums(NULL);
+                                       }
+                               | opt_label decl_start decl_stmts
+                                       {
+                                               plpgsql_ns_setlocal(false);
+                                               if ($3 != NULL) {
+                                                       $$.label = $3;
+                                               } else {
+                                                       $$.label = $1;
+                                               }
+                                               $$.n_initvars = plpgsql_add_initdatums(&($$.initvarnos));
+                                       }
+                               ;
+
+decl_start             : K_DECLARE
+                                       {
+                                               plpgsql_ns_setlocal(true);
+                                       }
+                               ;
+
+decl_stmts             : decl_stmts decl_stmt
+                                       {
+                                               $$ = $2;
+                                       }
+                               | decl_stmt
+                                       {
+                                               $$ = $1;
+                                       }
+                               ;
+
+decl_stmt              : '<' '<' opt_lblname '>' '>'
+                                       {
+                                               $$ = $3;
+                                       }
+                               | K_DECLARE
+                                       {
+                                               $$ = NULL;
+                                       }
+                               | decl_statement
+                                       {
+                                               $$ = NULL;
+                                       }
+                               ;
 
 decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval
-                   {
-                       PLpgSQL_var     *new;
-
-                       new = malloc(sizeof(PLpgSQL_var));
-
-                       new->dtype      = PLPGSQL_DTYPE_VAR;
-                       new->refname    = $1.name;
-                       new->lineno     = $1.lineno;
-
-                       new->datatype   = $3;
-                       new->isconst    = $2;
-                       new->notnull    = $4;
-                       new->default_val = $5;
-
-                       plpgsql_adddatum((PLpgSQL_datum *)new);
-                       plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
-                                               $1.name);
-                   }
-               | decl_varname K_RECORD ';'
-                   {
-                       PLpgSQL_rec     *new;
-
-                       new = malloc(sizeof(PLpgSQL_var));
-
-                       new->dtype      = PLPGSQL_DTYPE_REC;
-                       new->refname    = $1.name;
-                       new->lineno     = $1.lineno;
-
-                       plpgsql_adddatum((PLpgSQL_datum *)new);
-                       plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, new->recno,
-                                               $1.name);
-                   }
-               | decl_varname decl_rowtype ';'
-                   {
-                       $2->dtype       = PLPGSQL_DTYPE_ROW;
-                       $2->refname     = $1.name;
-                       $2->lineno      = $1.lineno;
-
-                       plpgsql_adddatum((PLpgSQL_datum *)$2);
-                       plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, $2->rowno,
-                                               $1.name);
-                   }
-               | decl_varname K_ALIAS K_FOR decl_aliasitem ';'
-                   {
-                       plpgsql_ns_additem($4->itemtype,
-                                       $4->itemno, $1.name);
-                   }
-               | K_RENAME decl_renname K_TO decl_renname ';'
-                   {
-                       plpgsql_ns_rename($2, $4);
-                   }
-               ;
+                                       {
+                                               PLpgSQL_var             *new;
+
+                                               new = malloc(sizeof(PLpgSQL_var));
+
+                                               new->dtype              = PLPGSQL_DTYPE_VAR;
+                                               new->refname    = $1.name;
+                                               new->lineno             = $1.lineno;
+
+                                               new->datatype   = $3;
+                                               new->isconst    = $2;
+                                               new->notnull    = $4;
+                                               new->default_val = $5;
+
+                                               plpgsql_adddatum((PLpgSQL_datum *)new);
+                                               plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
+                                                                                               $1.name);
+                                       }
+                               | decl_varname K_RECORD ';'
+                                       {
+                                               PLpgSQL_rec             *new;
+
+                                               new = malloc(sizeof(PLpgSQL_var));
+
+                                               new->dtype              = PLPGSQL_DTYPE_REC;
+                                               new->refname    = $1.name;
+                                               new->lineno             = $1.lineno;
+
+                                               plpgsql_adddatum((PLpgSQL_datum *)new);
+                                               plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, new->recno,
+                                                                                               $1.name);
+                                       }
+                               | decl_varname decl_rowtype ';'
+                                       {
+                                               $2->dtype               = PLPGSQL_DTYPE_ROW;
+                                               $2->refname             = $1.name;
+                                               $2->lineno              = $1.lineno;
+
+                                               plpgsql_adddatum((PLpgSQL_datum *)$2);
+                                               plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, $2->rowno,
+                                                                                               $1.name);
+                                       }
+                               | decl_varname K_ALIAS K_FOR decl_aliasitem ';'
+                                       {
+                                               plpgsql_ns_additem($4->itemtype,
+                                                                               $4->itemno, $1.name);
+                                       }
+                               | K_RENAME decl_renname K_TO decl_renname ';'
+                                       {
+                                               plpgsql_ns_rename($2, $4);
+                                       }
+                               ;
 
 decl_aliasitem : T_WORD
-                   {
-                       PLpgSQL_nsitem *nsi;
-                       char    *name;
-
-                       plpgsql_ns_setlocal(false);
-                       name = plpgsql_tolower(yytext);
-                       if (name[0] != '$') {
-                           elog(ERROR, "can only alias positional parameters");
-                       }
-                       nsi = plpgsql_ns_lookup(name, NULL);
-                       if (nsi == NULL) {
-                           elog(ERROR, "function has no parameter %s", name);
-                       }
-
-                       plpgsql_ns_setlocal(true);
-
-                       $$ = nsi;
-                   }
-               ;
+                                       {
+                                               PLpgSQL_nsitem *nsi;
+                                               char    *name;
+
+                                               plpgsql_ns_setlocal(false);
+                                               name = plpgsql_tolower(yytext);
+                                               if (name[0] != '$') {
+                                                       elog(ERROR, "can only alias positional parameters");
+                                               }
+                                               nsi = plpgsql_ns_lookup(name, NULL);
+                                               if (nsi == NULL) {
+                                                       elog(ERROR, "function has no parameter %s", name);
+                                               }
+
+                                               plpgsql_ns_setlocal(true);
+
+                                               $$ = nsi;
+                                       }
+                               ;
 
 decl_rowtype   : T_ROW
-                   {
-                       $$ = yylval.row;
-                   }
-               ;
+                                       {
+                                               $$ = yylval.row;
+                                       }
+                               ;
 
 decl_varname   : T_WORD
-                   {
-                               /* name should be malloc'd for use as varname */
-                               $$.name = strdup(plpgsql_tolower(yytext));
-                               $$.lineno  = yylineno;
-                   }
-               ;
+                                       {
+                                                               /* name should be malloc'd for use as varname */
+                                                               $$.name = strdup(plpgsql_tolower(yytext));
+                                                               $$.lineno  = yylineno;
+                                       }
+                               ;
 
 decl_renname   : T_WORD
-                   {
-                               /* the result must be palloc'd, see plpgsql_ns_rename */
-                       $$ = plpgsql_tolower(yytext);
-                   }
-               ;
-
-decl_const     :
-                   { $$ = 0; }
-               | K_CONSTANT
-                   { $$ = 1; }
-               ;
+                                       {
+                                                               /* the result must be palloc'd, see plpgsql_ns_rename */
+                                               $$ = plpgsql_tolower(yytext);
+                                       }
+                               ;
+
+decl_const             :
+                                       { $$ = 0; }
+                               | K_CONSTANT
+                                       { $$ = 1; }
+                               ;
 
 decl_datatype  : decl_dtypename
-                   {
-                       $$ = $1;
-                   }
-               ;
+                                       {
+                                               $$ = $1;
+                                       }
+                               ;
 
 decl_dtypename : T_DTYPE
-                   {
-                       $$ = yylval.dtype;
-                   }
-               | T_CHAR decl_atttypmod
-                   {
-                       if ($2 < 0) {
-                           plpgsql_parse_word("char");
-                           $$ = yylval.dtype;
-                       } else {
-                           plpgsql_parse_word("bpchar");
-                           $$ = yylval.dtype;
-                           $$->atttypmod = $2;
-                       }
-                   }
-               | T_VARCHAR decl_atttypmod
-                   {
-                       plpgsql_parse_word("varchar");
-                       $$ = yylval.dtype;
-                       $$->atttypmod = $2;
-                   }
-               | T_BPCHAR '(' decl_atttypmodval ')'
-                   {
-                       plpgsql_parse_word("bpchar");
-                       $$ = yylval.dtype;
-                       $$->atttypmod = $3;
-                   }
-               ;
+                                       {
+                                               $$ = yylval.dtype;
+                                       }
+                               | T_CHAR decl_atttypmod
+                                       {
+                                               if ($2 < 0) {
+                                                       plpgsql_parse_word("char");
+                                                       $$ = yylval.dtype;
+                                               } else {
+                                                       plpgsql_parse_word("bpchar");
+                                                       $$ = yylval.dtype;
+                                                       $$->atttypmod = $2;
+                                               }
+                                       }
+                               | T_VARCHAR decl_atttypmod
+                                       {
+                                               plpgsql_parse_word("varchar");
+                                               $$ = yylval.dtype;
+                                               $$->atttypmod = $2;
+                                       }
+                               | T_BPCHAR '(' decl_atttypmodval ')'
+                                       {
+                                               plpgsql_parse_word("bpchar");
+                                               $$ = yylval.dtype;
+                                               $$->atttypmod = $3;
+                                       }
+                               ;
 
 decl_atttypmod :
-                   {
-                       $$ = -1;
-                   }
-               | '(' decl_atttypmodval ')'
-                   {
-                       $$ = $2;
-                   }
-               ;
-
-decl_atttypmodval      : T_NUMBER
-                   {
-                       $$ = pg_atoi(yytext, sizeof(int16), '\0') + VARHDRSZ;
-                   }
-               ;
+                                       {
+                                               $$ = -1;
+                                       }
+                               | '(' decl_atttypmodval ')'
+                                       {
+                                               $$ = $2;
+                                       }
+                               ;
+
+decl_atttypmodval              : T_NUMBER
+                                       {
+                                               $$ = pg_atoi(yytext, sizeof(int16), '\0') + VARHDRSZ;
+                                       }
+                               ;
 
 decl_notnull   :
-                   { $$ = 0; }
-               | K_NOT K_NULL
-                   { $$ = 1; }
-               ;
-
-decl_defval    : ';'
-                   { $$ = NULL; }
-               | decl_defkey
-                   {
-                       int             tok;
-                       int             lno;
-                       PLpgSQL_dstring ds;
-                       PLpgSQL_expr    *expr;
-
-                       lno = yylineno;
-                       expr = malloc(sizeof(PLpgSQL_expr));
-                       plpgsql_dstring_init(&ds);
-                       plpgsql_dstring_append(&ds, "SELECT ");
-
-                       expr->dtype   = PLPGSQL_DTYPE_EXPR;
-                       expr->plan    = NULL;
-                       expr->nparams = 0;
-
-                       tok = yylex();
-                       switch (tok) {
-                           case 0:
-                               plpgsql_error_lineno = lno;
-                               plpgsql_comperrinfo();
-                               elog(ERROR, "unexpected end of file");
-                           case K_NULL:
-                               if (yylex() != ';') {
-                                   plpgsql_error_lineno = lno;
-                                   plpgsql_comperrinfo();
-                                   elog(ERROR, "expectec ; after NULL");
-                               }
-                               free(expr);
-                               plpgsql_dstring_free(&ds);
-
-                               $$ = NULL;
-                               break;
-
-                           default:
-                               plpgsql_dstring_append(&ds, yytext);
-                               while ((tok = yylex()) != ';') {
-                                   if (tok == 0) {
-                                       plpgsql_error_lineno = lno;
-                                       plpgsql_comperrinfo();
-                                       elog(ERROR, "unterminated default value");
-                                   }
-                                   if (plpgsql_SpaceScanned) {
-                                       plpgsql_dstring_append(&ds, " ");
-                                   }
-                                   plpgsql_dstring_append(&ds, yytext);
-                               }
-                               expr->query = strdup(plpgsql_dstring_get(&ds));
-                               plpgsql_dstring_free(&ds);
-
-                               $$ = expr;
-                               break;
-                       }
-                   }
-               ;
-
-decl_defkey    : K_ASSIGN
-               | K_DEFAULT
-
-proc_sect      :
-                       {
-                               PLpgSQL_stmts   *new;
-
-                               new = malloc(sizeof(PLpgSQL_stmts));
-                               memset(new, 0, sizeof(PLpgSQL_stmts));
-                               $$ = new;
-                       }
-               | proc_stmts
-                       {
-                               $$ = $1;
-                       }
-               ;
-
-proc_stmts     : proc_stmts proc_stmt
-                       {
-                               if ($1->stmts_used == $1->stmts_alloc) {
-                                   $1->stmts_alloc *= 2;
-                                   $1->stmts = realloc($1->stmts, sizeof(PLpgSQL_stmt *) * $1->stmts_alloc);
-                               }
-                               $1->stmts[$1->stmts_used++] = (struct PLpgSQL_stmt *)$2;
-
-                               $$ = $1;
-                       }
-               | proc_stmt
-                       {
-                               PLpgSQL_stmts   *new;
-
-                               new = malloc(sizeof(PLpgSQL_stmts));
-                               memset(new, 0, sizeof(PLpgSQL_stmts));
-
-                               new->stmts_alloc = 64;
-                               new->stmts_used  = 1;
-                               new->stmts = malloc(sizeof(PLpgSQL_stmt *) * new->stmts_alloc);
-                               new->stmts[0] = (struct PLpgSQL_stmt *)$1;
-
-                               $$ = new;
-                       }
-               ;
-
-proc_stmt      : pl_block
-                       { $$ = $1; }
-               | stmt_assign
-                       { $$ = $1; }
-               | stmt_if
-                       { $$ = $1; }
-               | stmt_loop
-                       { $$ = $1; }
-               | stmt_while
-                       { $$ = $1; }
-               | stmt_fori
-                       { $$ = $1; }
-               | stmt_fors
-                       { $$ = $1; }
-               | stmt_select
-                       { $$ = $1; }
-               | stmt_exit
-                       { $$ = $1; }
-               | stmt_return
-                       { $$ = $1; }
-               | stmt_raise
-                       { $$ = $1; }
-               | stmt_execsql
-                       { $$ = $1; }
-               | stmt_dynexecute
-                       { $$ = $1; }
-               | stmt_dynfors
-                       { $$ = $1; }
-               | stmt_perform
-                       { $$ = $1; }
-               | stmt_getdiag
-                       { $$ = $1; }
-               ;
+                                       { $$ = 0; }
+                               | K_NOT K_NULL
+                                       { $$ = 1; }
+                               ;
+
+decl_defval            : ';'
+                                       { $$ = NULL; }
+                               | decl_defkey
+                                       {
+                                               int                             tok;
+                                               int                             lno;
+                                               PLpgSQL_dstring ds;
+                                               PLpgSQL_expr    *expr;
+
+                                               lno = yylineno;
+                                               expr = malloc(sizeof(PLpgSQL_expr));
+                                               plpgsql_dstring_init(&ds);
+                                               plpgsql_dstring_append(&ds, "SELECT ");
+
+                                               expr->dtype   = PLPGSQL_DTYPE_EXPR;
+                                               expr->plan        = NULL;
+                                               expr->nparams = 0;
+
+                                               tok = yylex();
+                                               switch (tok) {
+                                                       case 0:
+                                                               plpgsql_error_lineno = lno;
+                                                               plpgsql_comperrinfo();
+                                                               elog(ERROR, "unexpected end of file");
+                                                       case K_NULL:
+                                                               if (yylex() != ';') {
+                                                                       plpgsql_error_lineno = lno;
+                                                                       plpgsql_comperrinfo();
+                                                                       elog(ERROR, "expectec ; after NULL");
+                                                               }
+                                                               free(expr);
+                                                               plpgsql_dstring_free(&ds);
+
+                                                               $$ = NULL;
+                                                               break;
+
+                                                       default:
+                                                               plpgsql_dstring_append(&ds, yytext);
+                                                               while ((tok = yylex()) != ';') {
+                                                                       if (tok == 0) {
+                                                                               plpgsql_error_lineno = lno;
+                                                                               plpgsql_comperrinfo();
+                                                                               elog(ERROR, "unterminated default value");
+                                                                       }
+                                                                       if (plpgsql_SpaceScanned) {
+                                                                               plpgsql_dstring_append(&ds, " ");
+                                                                       }
+                                                                       plpgsql_dstring_append(&ds, yytext);
+                                                               }
+                                                               expr->query = strdup(plpgsql_dstring_get(&ds));
+                                                               plpgsql_dstring_free(&ds);
+
+                                                               $$ = expr;
+                                                               break;
+                                               }
+                                       }
+                               ;
+
+decl_defkey            : K_ASSIGN
+                               | K_DEFAULT
+
+proc_sect              :
+                                               {
+                                                               PLpgSQL_stmts   *new;
+
+                                                               new = malloc(sizeof(PLpgSQL_stmts));
+                                                               memset(new, 0, sizeof(PLpgSQL_stmts));
+                                                               $$ = new;
+                                               }
+                               | proc_stmts
+                                               {
+                                                               $$ = $1;
+                                               }
+                               ;
+
+proc_stmts             : proc_stmts proc_stmt
+                                               {
+                                                               if ($1->stmts_used == $1->stmts_alloc) {
+                                                                       $1->stmts_alloc *= 2;
+                                                                       $1->stmts = realloc($1->stmts, sizeof(PLpgSQL_stmt *) * $1->stmts_alloc);
+                                                               }
+                                                               $1->stmts[$1->stmts_used++] = (struct PLpgSQL_stmt *)$2;
+
+                                                               $$ = $1;
+                                               }
+                               | proc_stmt
+                                               {
+                                                               PLpgSQL_stmts   *new;
+
+                                                               new = malloc(sizeof(PLpgSQL_stmts));
+                                                               memset(new, 0, sizeof(PLpgSQL_stmts));
+
+                                                               new->stmts_alloc = 64;
+                                                               new->stmts_used  = 1;
+                                                               new->stmts = malloc(sizeof(PLpgSQL_stmt *) * new->stmts_alloc);
+                                                               new->stmts[0] = (struct PLpgSQL_stmt *)$1;
+
+                                                               $$ = new;
+                                               }
+                               ;
+
+proc_stmt              : pl_block
+                                               { $$ = $1; }
+                               | stmt_assign
+                                               { $$ = $1; }
+                               | stmt_if
+                                               { $$ = $1; }
+                               | stmt_loop
+                                               { $$ = $1; }
+                               | stmt_while
+                                               { $$ = $1; }
+                               | stmt_fori
+                                               { $$ = $1; }
+                               | stmt_fors
+                                               { $$ = $1; }
+                               | stmt_select
+                                               { $$ = $1; }
+                               | stmt_exit
+                                               { $$ = $1; }
+                               | stmt_return
+                                               { $$ = $1; }
+                               | stmt_raise
+                                               { $$ = $1; }
+                               | stmt_execsql
+                                               { $$ = $1; }
+                               | stmt_dynexecute
+                                               { $$ = $1; }
+                               | stmt_dynfors
+                                               { $$ = $1; }
+                               | stmt_perform
+                                               { $$ = $1; }
+                               | stmt_getdiag
+                                               { $$ = $1; }
+                               ;
 
 stmt_perform   : K_PERFORM lno expr_until_semi
-                   {
-                       PLpgSQL_stmt_assign *new;
+                                       {
+                                               PLpgSQL_stmt_assign *new;
 
-                       new = malloc(sizeof(PLpgSQL_stmt_assign));
-                       memset(new, 0, sizeof(PLpgSQL_stmt_assign));
+                                               new = malloc(sizeof(PLpgSQL_stmt_assign));
+                                               memset(new, 0, sizeof(PLpgSQL_stmt_assign));
 
-                       new->cmd_type = PLPGSQL_STMT_ASSIGN;
-                       new->lineno   = $2;
-                       new->varno = -1;
-                       new->expr  = $3;
+                                               new->cmd_type = PLPGSQL_STMT_ASSIGN;
+                                               new->lineno   = $2;
+                                               new->varno = -1;
+                                               new->expr  = $3;
 
-                       $$ = (PLpgSQL_stmt *)new;
-                   }
-               ;
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
+                               ;
 
-stmt_assign    : assign_var lno K_ASSIGN expr_until_semi
-                   {
-                       PLpgSQL_stmt_assign *new;
+stmt_assign            : assign_var lno K_ASSIGN expr_until_semi
+                                       {
+                                               PLpgSQL_stmt_assign *new;
 
-                       new = malloc(sizeof(PLpgSQL_stmt_assign));
-                       memset(new, 0, sizeof(PLpgSQL_stmt_assign));
+                                               new = malloc(sizeof(PLpgSQL_stmt_assign));
+                                               memset(new, 0, sizeof(PLpgSQL_stmt_assign));
 
-                       new->cmd_type = PLPGSQL_STMT_ASSIGN;
-                       new->lineno   = $2;
-                       new->varno = $1;
-                       new->expr  = $4;
+                                               new->cmd_type = PLPGSQL_STMT_ASSIGN;
+                                               new->lineno   = $2;
+                                               new->varno = $1;
+                                               new->expr  = $4;
 
-                       $$ = (PLpgSQL_stmt *)new;
-                   }
-               ;
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
+                               ;
 
 stmt_getdiag   : K_GET K_DIAGNOSTICS lno K_SELECT getdiag_items K_INTO getdiag_targets ';'
-                    {
-                        PLpgSQL_stmt_getdiag     *new;
-
-                        new = malloc(sizeof(PLpgSQL_stmt_getdiag));
-                        memset(new, 0, sizeof(PLpgSQL_stmt_getdiag));
-
-                        new->cmd_type = PLPGSQL_STMT_GETDIAG;
-                        new->lineno   = $3;
-                        new->nitems   = $5.nused;
-                        new->items    = malloc(sizeof(int) * $5.nused);
-                        new->ntargets = $7.nused;
-                        new->targets  = malloc(sizeof(int) * $7.nused);
-                       memcpy(new->items, $5.dtnums, sizeof(int) * $5.nused);
-                       memcpy(new->targets, $7.dtnums, sizeof(int) * $7.nused);
-
-                        if (new->nitems != new->ntargets) {
-                           plpgsql_error_lineno = new->lineno;
-                            plpgsql_comperrinfo();
-                            elog(ERROR, "number of diagnostic items does not match target list");
-                        };
-
-                        $$ = (PLpgSQL_stmt *)new;
-                    }
-                ;
+                                       {
+                                               PLpgSQL_stmt_getdiag     *new;
+
+                                               new = malloc(sizeof(PLpgSQL_stmt_getdiag));
+                                               memset(new, 0, sizeof(PLpgSQL_stmt_getdiag));
+
+                                               new->cmd_type = PLPGSQL_STMT_GETDIAG;
+                                               new->lineno   = $3;
+                                               new->nitems   = $5.nused;
+                                               new->items        = malloc(sizeof(int) * $5.nused);
+                                               new->ntargets = $7.nused;
+                                               new->targets  = malloc(sizeof(int) * $7.nused);
+                                               memcpy(new->items, $5.dtnums, sizeof(int) * $5.nused);
+                                               memcpy(new->targets, $7.dtnums, sizeof(int) * $7.nused);
+
+                                               if (new->nitems != new->ntargets) {
+                                                       plpgsql_error_lineno = new->lineno;
+                                                       plpgsql_comperrinfo();
+                                                       elog(ERROR, "number of diagnostic items does not match target list");
+                                               };
+
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
+                               ;
 
 getdiag_items : getdiag_items ',' getdiag_item
-                    {
-                        if ($1.nused == $1.nalloc) {
-                            $1.nalloc *= 2;
-                            $1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc);
-                        }
-                        $1.dtnums[$1.nused++] = $3;
-
-                        $$.nalloc = $1.nalloc;
-                        $$.nused  = $1.nused;
-                        $$.dtnums = $1.dtnums;
-                    }
-               | getdiag_item
-                    {
-                        $$.nalloc = 1;
-                        $$.nused  = 1;
-                        $$.dtnums = palloc(sizeof(int) * $$.nalloc);
-                        $$.dtnums[0] = $1;
-                    }
-                ;
+                                       {
+                                               if ($1.nused == $1.nalloc) {
+                                                       $1.nalloc *= 2;
+                                                       $1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc);
+                                               }
+                                               $1.dtnums[$1.nused++] = $3;
+
+                                               $$.nalloc = $1.nalloc;
+                                               $$.nused  = $1.nused;
+                                               $$.dtnums = $1.dtnums;
+                                       }
+                               | getdiag_item
+                                       {
+                                               $$.nalloc = 1;
+                                               $$.nused  = 1;
+                                               $$.dtnums = palloc(sizeof(int) * $$.nalloc);
+                                               $$.dtnums[0] = $1;
+                                       }
+                               ;
 
 getdiag_item : K_PROCESSED
-                    {
-                        $$ = PLPGSQL_GETDIAG_PROCESSED;
-                    }
-               | K_RESULT
-                    {
-                        $$ = PLPGSQL_GETDIAG_RESULT;
-                    }
-               ;
+                                       {
+                                               $$ = PLPGSQL_GETDIAG_PROCESSED;
+                                       }
+                               | K_RESULT
+                                       {
+                                               $$ = PLPGSQL_GETDIAG_RESULT;
+                                       }
+                               ;
 
 getdiag_targets : getdiag_targets ',' getdiag_target
-                    {
-                        if ($1.nused == $1.nalloc) {
-                            $1.nalloc *= 2;
-                            $1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc);
-                        }
-                        $1.dtnums[$1.nused++] = $3;
-
-                        $$.nalloc = $1.nalloc;
-                        $$.nused  = $1.nused;
-                        $$.dtnums = $1.dtnums;
-                    }
-               | getdiag_target
-                    {
-                        $$.nalloc = 1;
-                        $$.nused  = 1;
-                        $$.dtnums = palloc(sizeof(int) * $$.nalloc);
-                        $$.dtnums[0] = $1;
-                    }
-                ;
-
-
-getdiag_target     : T_VARIABLE
-                    {
-                        if (yylval.var->isconst) {
-                            plpgsql_comperrinfo();
-                            elog(ERROR, "%s is declared CONSTANT; can not receive diagnostics", yylval.var->refname);
-                        }
-                        $$ = yylval.var->varno;
-                    }
-                | T_RECFIELD
-                    {
-                        $$ = yylval.recfield->rfno;
-                    }
-                ;
-
-assign_var     : T_VARIABLE
-                   {
-                       if (yylval.var->isconst) {
-                           plpgsql_comperrinfo();
-                           elog(ERROR, "%s is declared CONSTANT", yylval.var->refname);
-                       }
-                       $$ = yylval.var->varno;
-                   }
-               | T_RECFIELD
-                   {
-                       $$ = yylval.recfield->rfno;
-                   }
-               ;
-
-stmt_if                : K_IF lno expr_until_then proc_sect stmt_else K_END K_IF ';'
-                   {
-                       PLpgSQL_stmt_if *new;
-
-                       new = malloc(sizeof(PLpgSQL_stmt_if));
-                       memset(new, 0, sizeof(PLpgSQL_stmt_if));
-
-                       new->cmd_type   = PLPGSQL_STMT_IF;
-                       new->lineno     = $2;
-                       new->cond       = $3;
-                       new->true_body  = $4;
-                       new->false_body = $5;
-
-                       $$ = (PLpgSQL_stmt *)new;
-                   }
-               ;
-
-stmt_else      :
-                       {
-                               PLpgSQL_stmts   *new;
-
-                               new = malloc(sizeof(PLpgSQL_stmts));
-                               memset(new, 0, sizeof(PLpgSQL_stmts));
-                               $$ = new;
-                       }
-               | K_ELSE proc_sect
-                       { $$ = $2; }
-               ;
-
-stmt_loop      : opt_label K_LOOP lno loop_body
-                   {
-                       PLpgSQL_stmt_loop *new;
-
-                       new = malloc(sizeof(PLpgSQL_stmt_loop));
-                       memset(new, 0, sizeof(PLpgSQL_stmt_loop));
-
-                       new->cmd_type = PLPGSQL_STMT_LOOP;
-                       new->lineno   = $3;
-                       new->label    = $1;
-                       new->body     = $4;
-
-                       plpgsql_ns_pop();
-
-                       $$ = (PLpgSQL_stmt *)new;
-                   }
-               ;
-
-stmt_while     : opt_label K_WHILE lno expr_until_loop loop_body
-                   {
-                       PLpgSQL_stmt_while *new;
-
-                       new = malloc(sizeof(PLpgSQL_stmt_while));
-                       memset(new, 0, sizeof(PLpgSQL_stmt_while));
-
-                       new->cmd_type = PLPGSQL_STMT_WHILE;
-                       new->lineno   = $3;
-                       new->label    = $1;
-                       new->cond     = $4;
-                       new->body     = $5;
-
-                       plpgsql_ns_pop();
-
-                       $$ = (PLpgSQL_stmt *)new;
-                   }
-               ;
+                                       {
+                                               if ($1.nused == $1.nalloc) {
+                                                       $1.nalloc *= 2;
+                                                       $1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc);
+                                               }
+                                               $1.dtnums[$1.nused++] = $3;
+
+                                               $$.nalloc = $1.nalloc;
+                                               $$.nused  = $1.nused;
+                                               $$.dtnums = $1.dtnums;
+                                       }
+                               | getdiag_target
+                                       {
+                                               $$.nalloc = 1;
+                                               $$.nused  = 1;
+                                               $$.dtnums = palloc(sizeof(int) * $$.nalloc);
+                                               $$.dtnums[0] = $1;
+                                       }
+                               ;
+
+
+getdiag_target    : T_VARIABLE
+                                       {
+                                               if (yylval.var->isconst) {
+                                                       plpgsql_comperrinfo();
+                                                       elog(ERROR, "%s is declared CONSTANT; can not receive diagnostics", yylval.var->refname);
+                                               }
+                                               $$ = yylval.var->varno;
+                                       }
+                               | T_RECFIELD
+                                       {
+                                               $$ = yylval.recfield->rfno;
+                                       }
+                               ;
+
+
+assign_var             : T_VARIABLE
+                                       {
+                                               if (yylval.var->isconst) {
+                                                       plpgsql_comperrinfo();
+                                                       elog(ERROR, "%s is declared CONSTANT", yylval.var->refname);
+                                               }
+                                               $$ = yylval.var->varno;
+                                       }
+                               | T_RECFIELD
+                                       {
+                                               $$ = yylval.recfield->rfno;
+                                       }
+                               ;
+
+stmt_if                        : K_IF lno expr_until_then proc_sect stmt_else K_END K_IF ';'
+                                       {
+                                               PLpgSQL_stmt_if *new;
+
+                                               new = malloc(sizeof(PLpgSQL_stmt_if));
+                                               memset(new, 0, sizeof(PLpgSQL_stmt_if));
+
+                                               new->cmd_type   = PLPGSQL_STMT_IF;
+                                               new->lineno             = $2;
+                                               new->cond               = $3;
+                                               new->true_body  = $4;
+                                               new->false_body = $5;
+
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
+                               ;
+
+stmt_else              :
+                                               {
+                                                               PLpgSQL_stmts   *new;
+
+                                                               new = malloc(sizeof(PLpgSQL_stmts));
+                                                               memset(new, 0, sizeof(PLpgSQL_stmts));
+                                                               $$ = new;
+                                               }
+                               | K_ELSE proc_sect
+                                               { $$ = $2; }
+                               ;
+
+stmt_loop              : opt_label K_LOOP lno loop_body
+                                       {
+                                               PLpgSQL_stmt_loop *new;
+
+                                               new = malloc(sizeof(PLpgSQL_stmt_loop));
+                                               memset(new, 0, sizeof(PLpgSQL_stmt_loop));
+
+                                               new->cmd_type = PLPGSQL_STMT_LOOP;
+                                               new->lineno   = $3;
+                                               new->label        = $1;
+                                               new->body         = $4;
+
+                                               plpgsql_ns_pop();
+
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
+                               ;
+
+stmt_while             : opt_label K_WHILE lno expr_until_loop loop_body
+                                       {
+                                               PLpgSQL_stmt_while *new;
+
+                                               new = malloc(sizeof(PLpgSQL_stmt_while));
+                                               memset(new, 0, sizeof(PLpgSQL_stmt_while));
+
+                                               new->cmd_type = PLPGSQL_STMT_WHILE;
+                                               new->lineno   = $3;
+                                               new->label        = $1;
+                                               new->cond         = $4;
+                                               new->body         = $5;
+
+                                               plpgsql_ns_pop();
+
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
+                               ;
+
+stmt_fori              : opt_label K_FOR lno fori_var K_IN fori_lower expr_until_loop loop_body
+                                       {
+                                               PLpgSQL_stmt_fori               *new;
+
+                                               new = malloc(sizeof(PLpgSQL_stmt_fori));
+                                               memset(new, 0, sizeof(PLpgSQL_stmt_fori));
+
+                                               new->cmd_type = PLPGSQL_STMT_FORI;
+                                               new->lineno   = $3;
+                                               new->label        = $1;
+                                               new->var          = $4;
+                                               new->reverse  = $6.reverse;
+                                               new->lower        = $6.expr;
+                                               new->upper        = $7;
+                                               new->body         = $8;
+
+                                               plpgsql_ns_pop();
+
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
+                               ;
+
+fori_var               : fori_varname
+                                       {
+                                               PLpgSQL_var             *new;
+
+                                               new = malloc(sizeof(PLpgSQL_var));
 
-stmt_fori      : opt_label K_FOR lno fori_var K_IN fori_lower expr_until_loop loop_body
-                   {
-                       PLpgSQL_stmt_fori       *new;
+                                               new->dtype              = PLPGSQL_DTYPE_VAR;
+                                               new->refname    = $1.name;
+                                               new->lineno             = $1.lineno;
 
-                       new = malloc(sizeof(PLpgSQL_stmt_fori));
-                       memset(new, 0, sizeof(PLpgSQL_stmt_fori));
+                                               plpgsql_parse_word("integer");
 
-                       new->cmd_type = PLPGSQL_STMT_FORI;
-                       new->lineno   = $3;
-                       new->label    = $1;
-                       new->var      = $4;
-                       new->reverse  = $6.reverse;
-                       new->lower    = $6.expr;
-                       new->upper    = $7;
-                       new->body     = $8;
+                                               new->datatype   = yylval.dtype;
+                                               new->isconst    = false;
+                                               new->notnull    = false;
+                                               new->default_val = NULL;
 
-                       plpgsql_ns_pop();
+                                               plpgsql_adddatum((PLpgSQL_datum *)new);
+                                               plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
+                                                                                               $1.name);
 
-                       $$ = (PLpgSQL_stmt *)new;
-                   }
-               ;
+                                               plpgsql_add_initdatums(NULL);
 
-fori_var       : fori_varname
-                   {
-                       PLpgSQL_var     *new;
-
-                       new = malloc(sizeof(PLpgSQL_var));
-
-                       new->dtype      = PLPGSQL_DTYPE_VAR;
-                       new->refname    = $1.name;
-                       new->lineno     = $1.lineno;
-
-                       plpgsql_parse_word("integer");
-
-                       new->datatype   = yylval.dtype;
-                       new->isconst    = false;
-                       new->notnull    = false;
-                       new->default_val = NULL;
-
-                       plpgsql_adddatum((PLpgSQL_datum *)new);
-                       plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
-                                               $1.name);
-
-                       plpgsql_add_initdatums(NULL);
-
-                       $$ = new;
-                   }
-               ;
+                                               $$ = new;
+                                       }
+                               ;
 
 fori_varname   : T_VARIABLE
-                   {
-                       $$.name = strdup(yytext);
-                       $$.lineno = yylineno;
-                   }
-               | T_WORD
-                   {
-                       $$.name = strdup(yytext);
-                       $$.lineno = yylineno;
-                   }
-               ;
-
-fori_lower     :
-                   {
-                       int                     tok;
-                       int                     lno;
-                       PLpgSQL_dstring ds;
-                       int                     nparams = 0;
-                       int                     params[1024];
-                       char            buf[32];
-                       PLpgSQL_expr    *expr;
-                       int                     firsttok = 1;
-
-                       lno = yylineno;
-                       plpgsql_dstring_init(&ds);
-                       plpgsql_dstring_append(&ds, "SELECT ");
-
-                       $$.reverse = 0;
-                       while((tok = yylex()) != K_DOTDOT) {
-                           if (firsttok) {
-                               firsttok = 0;
-                               if (tok == K_REVERSE) {
-                                   $$.reverse = 1;
-                                   continue;
-                               }
-                           }
-                           if (tok == ';') break;
-                           if (plpgsql_SpaceScanned) {
-                               plpgsql_dstring_append(&ds, " ");
-                           }
-                           switch (tok) {
-                               case T_VARIABLE:
-                                   params[nparams] = yylval.var->varno;
-                                   sprintf(buf, " $%d ", ++nparams);
-                                   plpgsql_dstring_append(&ds, buf);
-                                   break;
-                                   
-                               case T_RECFIELD:
-                                   params[nparams] = yylval.recfield->rfno;
-                                   sprintf(buf, " $%d ", ++nparams);
-                                   plpgsql_dstring_append(&ds, buf);
-                                   break;
-                                   
-                               case T_TGARGV:
-                                   params[nparams] = yylval.trigarg->dno;
-                                   sprintf(buf, " $%d ", ++nparams);
-                                   plpgsql_dstring_append(&ds, buf);
-                                   break;
-                                   
-                               default:
-                                   if (tok == 0) {
-                                       plpgsql_error_lineno = lno;
-                                       plpgsql_comperrinfo();
-                                       elog(ERROR, "missing .. to terminate lower bound of for loop");
-                                   }
-                                   plpgsql_dstring_append(&ds, yytext);
-                                   break;
-                           }
-                       }
-
-                       expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
-                       expr->dtype             = PLPGSQL_DTYPE_EXPR;
-                       expr->query             = strdup(plpgsql_dstring_get(&ds));
-                       expr->plan              = NULL;
-                       expr->nparams   = nparams;
-                       while(nparams-- > 0) {
-                           expr->params[nparams] = params[nparams];
-                       }
-                       plpgsql_dstring_free(&ds);
-                       $$.expr = expr;
-                   }
-
-stmt_fors      : opt_label K_FOR lno fors_target K_IN K_SELECT expr_until_loop loop_body
-                   {
-                       PLpgSQL_stmt_fors       *new;
-
-                       new = malloc(sizeof(PLpgSQL_stmt_fors));
-                       memset(new, 0, sizeof(PLpgSQL_stmt_fors));
-
-                       new->cmd_type = PLPGSQL_STMT_FORS;
-                       new->lineno   = $3;
-                       new->label    = $1;
-                       switch ($4->dtype) {
-                           case PLPGSQL_DTYPE_REC:
-                               new->rec = $4;
-                               break;
-                           case PLPGSQL_DTYPE_ROW:
-                               new->row = (PLpgSQL_row *)$4;
-                               break;
-                           default:
-                               plpgsql_comperrinfo();
-                               elog(ERROR, "unknown dtype %d in stmt_fors", $4->dtype);
-                       }
-                       new->query = $7;
-                       new->body  = $8;
-
-                       plpgsql_ns_pop();
-
-                       $$ = (PLpgSQL_stmt *)new;
-                   }
+                                       {
+                                               $$.name = strdup(yytext);
+                                               $$.lineno = yylineno;
+                                       }
+                               | T_WORD
+                                       {
+                                               $$.name = strdup(yytext);
+                                               $$.lineno = yylineno;
+                                       }
+                               ;
+
+fori_lower             :
+                                       {
+                                               int                                             tok;
+                                               int                                             lno;
+                                               PLpgSQL_dstring ds;
+                                               int                                             nparams = 0;
+                                               int                                             params[1024];
+                                               char                    buf[32];
+                                               PLpgSQL_expr    *expr;
+                                               int                                             firsttok = 1;
+
+                                               lno = yylineno;
+                                               plpgsql_dstring_init(&ds);
+                                               plpgsql_dstring_append(&ds, "SELECT ");
+
+                                               $$.reverse = 0;
+                                               while((tok = yylex()) != K_DOTDOT) {
+                                                       if (firsttok) {
+                                                               firsttok = 0;
+                                                               if (tok == K_REVERSE) {
+                                                                       $$.reverse = 1;
+                                                                       continue;
+                                                               }
+                                                       }
+                                                       if (tok == ';') break;
+                                                       if (plpgsql_SpaceScanned) {
+                                                               plpgsql_dstring_append(&ds, " ");
+                                                       }
+                                                       switch (tok) {
+                                                               case T_VARIABLE:
+                                                                       params[nparams] = yylval.var->varno;
+                                                                       sprintf(buf, " $%d ", ++nparams);
+                                                                       plpgsql_dstring_append(&ds, buf);
+                                                                       break;
+
+                                                               case T_RECFIELD:
+                                                                       params[nparams] = yylval.recfield->rfno;
+                                                                       sprintf(buf, " $%d ", ++nparams);
+                                                                       plpgsql_dstring_append(&ds, buf);
+                                                                       break;
+
+                                                               case T_TGARGV:
+                                                                       params[nparams] = yylval.trigarg->dno;
+                                                                       sprintf(buf, " $%d ", ++nparams);
+                                                                       plpgsql_dstring_append(&ds, buf);
+                                                                       break;
+
+                                                               default:
+                                                                       if (tok == 0) {
+                                                                               plpgsql_error_lineno = lno;
+                                                                               plpgsql_comperrinfo();
+                                                                               elog(ERROR, "missing .. to terminate lower bound of for loop");
+                                                                       }
+                                                                       plpgsql_dstring_append(&ds, yytext);
+                                                                       break;
+                                                       }
+                                               }
+
+                                               expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
+                                               expr->dtype                             = PLPGSQL_DTYPE_EXPR;
+                                               expr->query                             = strdup(plpgsql_dstring_get(&ds));
+                                               expr->plan                              = NULL;
+                                               expr->nparams   = nparams;
+                                               while(nparams-- > 0) {
+                                                       expr->params[nparams] = params[nparams];
+                                               }
+                                               plpgsql_dstring_free(&ds);
+                                               $$.expr = expr;
+                                       }
+
+stmt_fors              : opt_label K_FOR lno fors_target K_IN K_SELECT expr_until_loop loop_body
+                                       {
+                                               PLpgSQL_stmt_fors               *new;
+
+                                               new = malloc(sizeof(PLpgSQL_stmt_fors));
+                                               memset(new, 0, sizeof(PLpgSQL_stmt_fors));
+
+                                               new->cmd_type = PLPGSQL_STMT_FORS;
+                                               new->lineno   = $3;
+                                               new->label        = $1;
+                                               switch ($4->dtype) {
+                                                       case PLPGSQL_DTYPE_REC:
+                                                               new->rec = $4;
+                                                               break;
+                                                       case PLPGSQL_DTYPE_ROW:
+                                                               new->row = (PLpgSQL_row *)$4;
+                                                               break;
+                                                       default:
+                                                               plpgsql_comperrinfo();
+                                                               elog(ERROR, "unknown dtype %d in stmt_fors", $4->dtype);
+                                               }
+                                               new->query = $7;
+                                               new->body  = $8;
+
+                                               plpgsql_ns_pop();
+
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
 
 stmt_dynfors : opt_label K_FOR lno fors_target K_IN K_EXECUTE expr_until_loop loop_body
-                   {
-                       PLpgSQL_stmt_dynfors    *new;
-
-                       new = malloc(sizeof(PLpgSQL_stmt_dynfors));
-                       memset(new, 0, sizeof(PLpgSQL_stmt_dynfors));
-
-                       new->cmd_type = PLPGSQL_STMT_DYNFORS;
-                       new->lineno   = $3;
-                       new->label    = $1;
-                       switch ($4->dtype) {
-                           case PLPGSQL_DTYPE_REC:
-                               new->rec = $4;
-                               break;
-                           case PLPGSQL_DTYPE_ROW:
-                               new->row = (PLpgSQL_row *)$4;
-                               break;
-                           default:
-                               plpgsql_comperrinfo();
-                               elog(ERROR, "unknown dtype %d in stmt_dynfors", $4->dtype);
-                       }
-                       new->query = $7;
-                       new->body  = $8;
-
-                       plpgsql_ns_pop();
-
-                       $$ = (PLpgSQL_stmt *)new;
-                   }
-
-fors_target    : T_RECORD
-                   {
-                       $$ = yylval.rec;
-                   }
-               | T_ROW
-                   {
-                       $$ = (PLpgSQL_rec *)(yylval.row);
-                   }
-               ;
-
-stmt_select    : K_SELECT lno
-                   {
-                       $$ = make_select_stmt();
-                       $$->lineno = $2;
-                   }
-               ;
-
-stmt_exit      : K_EXIT lno opt_exitlabel opt_exitcond
-                   {
-                       PLpgSQL_stmt_exit *new;
-
-                       new = malloc(sizeof(PLpgSQL_stmt_exit));
-                       memset(new, 0, sizeof(PLpgSQL_stmt_exit));
-
-                       new->cmd_type = PLPGSQL_STMT_EXIT;
-                       new->lineno   = $2;
-                       new->label    = $3;
-                       new->cond     = $4;
-
-                       $$ = (PLpgSQL_stmt *)new;
-                   }
-               ;
-
-stmt_return    : K_RETURN lno
-                   {
-                       PLpgSQL_stmt_return *new;
-                       PLpgSQL_expr    *expr = NULL;
-                       int             tok;
-
-                       new = malloc(sizeof(PLpgSQL_stmt_return));
-                       memset(new, 0, sizeof(PLpgSQL_stmt_return));
-
-                       if (plpgsql_curr_compile->fn_retistuple) {
-                           new->retistuple = true;
-                           new->retrecno   = -1;
-                           switch (tok = yylex()) {
-                               case K_NULL:
-                                   expr = NULL;
-                                   break;
-
-                               case T_ROW:
-                                   expr = make_tupret_expr(yylval.row);
-                                   break;
-
-                               case T_RECORD:
-                                   new->retrecno = yylval.rec->recno;
-                                   expr = NULL;
-                                   break;
-
-                               default:
-                                   yyerror("return type mismatch in function returning table row");
-                                   break;
-                           }
-                           if (yylex() != ';') {
-                               yyerror("expected ';'");
-                           }
-                       } else {
-                           new->retistuple = false;
-                           expr = plpgsql_read_expression(';', ";");
-                       }
-
-                       new->cmd_type = PLPGSQL_STMT_RETURN;
-                       new->lineno   = $2;
-                       new->expr     = expr;
-
-                       $$ = (PLpgSQL_stmt *)new;
-                   }
-               ;
-
-stmt_raise     : K_RAISE lno raise_level raise_msg raise_params ';'
-                   {
-                       PLpgSQL_stmt_raise      *new;
-
-                       new = malloc(sizeof(PLpgSQL_stmt_raise));
-
-                       new->cmd_type   = PLPGSQL_STMT_RAISE;
-                       new->lineno     = $2;
-                       new->elog_level = $3;
-                       new->message    = $4;
-                       new->nparams    = $5.nused;
-                       new->params     = malloc(sizeof(int) * $5.nused);
-                       memcpy(new->params, $5.dtnums, sizeof(int) * $5.nused);
-
-                       $$ = (PLpgSQL_stmt *)new;
-                   }
-               | K_RAISE lno raise_level raise_msg ';'
-                   {
-                       PLpgSQL_stmt_raise      *new;
-
-                       new = malloc(sizeof(PLpgSQL_stmt_raise));
-
-                       new->cmd_type   = PLPGSQL_STMT_RAISE;
-                       new->lineno     = $2;
-                       new->elog_level = $3;
-                       new->message    = $4;
-                       new->nparams    = 0;
-                       new->params     = NULL;
-
-                       $$ = (PLpgSQL_stmt *)new;
-                   }
-               ;
-
-raise_msg      : T_STRING
-                   {
-                       $$ = strdup(yytext);
-                   }
-               ;
-
-raise_level    : K_EXCEPTION
-                   {
-                       $$ = ERROR;
-                   }
-               | K_NOTICE
-                   {
-                       $$ = NOTICE;
-                   }
-               | K_DEBUG
-                   {
-                       $$ = DEBUG;
-                   }
-               ;
+                                       {
+                                               PLpgSQL_stmt_dynfors    *new;
+
+                                               new = malloc(sizeof(PLpgSQL_stmt_dynfors));
+                                               memset(new, 0, sizeof(PLpgSQL_stmt_dynfors));
+
+                                               new->cmd_type = PLPGSQL_STMT_DYNFORS;
+                                               new->lineno   = $3;
+                                               new->label        = $1;
+                                               switch ($4->dtype) {
+                                                       case PLPGSQL_DTYPE_REC:
+                                                               new->rec = $4;
+                                                               break;
+                                                       case PLPGSQL_DTYPE_ROW:
+                                                               new->row = (PLpgSQL_row *)$4;
+                                                               break;
+                                                       default:
+                                                               plpgsql_comperrinfo();
+                                                               elog(ERROR, "unknown dtype %d in stmt_dynfors", $4->dtype);
+                                               }
+                                               new->query = $7;
+                                               new->body  = $8;
+
+                                               plpgsql_ns_pop();
+
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
+
+fors_target            : T_RECORD
+                                       {
+                                               $$ = yylval.rec;
+                                       }
+                               | T_ROW
+                                       {
+                                               $$ = (PLpgSQL_rec *)(yylval.row);
+                                       }
+                               ;
+
+stmt_select            : K_SELECT lno
+                                       {
+                                               $$ = make_select_stmt();
+                                               $$->lineno = $2;
+                                       }
+                               ;
+
+stmt_exit              : K_EXIT lno opt_exitlabel opt_exitcond
+                                       {
+                                               PLpgSQL_stmt_exit *new;
+
+                                               new = malloc(sizeof(PLpgSQL_stmt_exit));
+                                               memset(new, 0, sizeof(PLpgSQL_stmt_exit));
+
+                                               new->cmd_type = PLPGSQL_STMT_EXIT;
+                                               new->lineno   = $2;
+                                               new->label        = $3;
+                                               new->cond         = $4;
+
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
+                               ;
+
+stmt_return            : K_RETURN lno
+                                       {
+                                               PLpgSQL_stmt_return *new;
+                                               PLpgSQL_expr    *expr = NULL;
+                                               int                             tok;
+
+                                               new = malloc(sizeof(PLpgSQL_stmt_return));
+                                               memset(new, 0, sizeof(PLpgSQL_stmt_return));
+
+                                               if (plpgsql_curr_compile->fn_retistuple) {
+                                                       new->retistuple = true;
+                                                       new->retrecno   = -1;
+                                                       switch (tok = yylex()) {
+                                                               case K_NULL:
+                                                                       expr = NULL;
+                                                                       break;
+
+                                                               case T_ROW:
+                                                                       expr = make_tupret_expr(yylval.row);
+                                                                       break;
+
+                                                               case T_RECORD:
+                                                                       new->retrecno = yylval.rec->recno;
+                                                                       expr = NULL;
+                                                                       break;
+
+                                                               default:
+                                                                       yyerror("return type mismatch in function returning table row");
+                                                                       break;
+                                                       }
+                                                       if (yylex() != ';') {
+                                                               yyerror("expected ';'");
+                                                       }
+                                               } else {
+                                                       new->retistuple = false;
+                                                       expr = plpgsql_read_expression(';', ";");
+                                               }
+
+                                               new->cmd_type = PLPGSQL_STMT_RETURN;
+                                               new->lineno   = $2;
+                                               new->expr         = expr;
+
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
+                               ;
+
+stmt_raise             : K_RAISE lno raise_level raise_msg raise_params ';'
+                                       {
+                                               PLpgSQL_stmt_raise              *new;
+
+                                               new = malloc(sizeof(PLpgSQL_stmt_raise));
+
+                                               new->cmd_type   = PLPGSQL_STMT_RAISE;
+                                               new->lineno             = $2;
+                                               new->elog_level = $3;
+                                               new->message    = $4;
+                                               new->nparams    = $5.nused;
+                                               new->params             = malloc(sizeof(int) * $5.nused);
+                                               memcpy(new->params, $5.dtnums, sizeof(int) * $5.nused);
+
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
+                               | K_RAISE lno raise_level raise_msg ';'
+                                       {
+                                               PLpgSQL_stmt_raise              *new;
+
+                                               new = malloc(sizeof(PLpgSQL_stmt_raise));
+
+                                               new->cmd_type   = PLPGSQL_STMT_RAISE;
+                                               new->lineno             = $2;
+                                               new->elog_level = $3;
+                                               new->message    = $4;
+                                               new->nparams    = 0;
+                                               new->params             = NULL;
+
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
+                               ;
+
+raise_msg              : T_STRING
+                                       {
+                                               $$ = strdup(yytext);
+                                       }
+                               ;
+
+raise_level            : K_EXCEPTION
+                                       {
+                                               $$ = ERROR;
+                                       }
+                               | K_NOTICE
+                                       {
+                                               $$ = NOTICE;
+                                       }
+                               | K_DEBUG
+                                       {
+                                               $$ = DEBUG;
+                                       }
+                               ;
 
 raise_params   : raise_params raise_param
-                   {
-                       if ($1.nused == $1.nalloc) {
-                           $1.nalloc *= 2;
-                           $1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc);
-                       }
-                       $1.dtnums[$1.nused++] = $2;
-
-                       $$.nalloc = $1.nalloc;
-                       $$.nused  = $1.nused;
-                       $$.dtnums = $1.dtnums;
-                   }
-               | raise_param
-                   {
-                       $$.nalloc = 1;
-                       $$.nused  = 1;
-                       $$.dtnums = palloc(sizeof(int) * $$.nalloc);
-                       $$.dtnums[0] = $1;
-                   }
-               ;
-
-raise_param    : ',' T_VARIABLE
-                   {
-                       $$ = yylval.var->varno;
-                   }
-               | ',' T_RECFIELD
-                   {
-                       $$ = yylval.recfield->rfno;
-                   }
-               | ',' T_TGARGV
-                   {
-                       $$ = yylval.trigarg->dno;
-                   }
-               ;
-
-loop_body      : proc_sect K_END K_LOOP ';'
-                   { $$ = $1; }
-               ;
+                                       {
+                                               if ($1.nused == $1.nalloc) {
+                                                       $1.nalloc *= 2;
+                                                       $1.dtnums = repalloc($1.dtnums, sizeof(int) * $1.nalloc);
+                                               }
+                                               $1.dtnums[$1.nused++] = $2;
+
+                                               $$.nalloc = $1.nalloc;
+                                               $$.nused  = $1.nused;
+                                               $$.dtnums = $1.dtnums;
+                                       }
+                               | raise_param
+                                       {
+                                               $$.nalloc = 1;
+                                               $$.nused  = 1;
+                                               $$.dtnums = palloc(sizeof(int) * $$.nalloc);
+                                               $$.dtnums[0] = $1;
+                                       }
+                               ;
+
+raise_param            : ',' T_VARIABLE
+                                       {
+                                               $$ = yylval.var->varno;
+                                       }
+                               | ',' T_RECFIELD
+                                       {
+                                               $$ = yylval.recfield->rfno;
+                                       }
+                               | ',' T_TGARGV
+                                       {
+                                               $$ = yylval.trigarg->dno;
+                                       }
+                               ;
+
+loop_body              : proc_sect K_END K_LOOP ';'
+                                       { $$ = $1; }
+                               ;
 
 stmt_execsql   : execsql_start lno
-                   {
-                       PLpgSQL_stmt_execsql    *new;
+                                       {
+                                               PLpgSQL_stmt_execsql    *new;
 
-                       new = malloc(sizeof(PLpgSQL_stmt_execsql));
-                       new->cmd_type = PLPGSQL_STMT_EXECSQL;
-                       new->lineno   = $2;
-                       new->sqlstmt  = read_sqlstmt(';', ";", $1);
+                                               new = malloc(sizeof(PLpgSQL_stmt_execsql));
+                                               new->cmd_type = PLPGSQL_STMT_EXECSQL;
+                                               new->lineno   = $2;
+                                               new->sqlstmt  = read_sqlstmt(';', ";", $1);
 
-                       $$ = (PLpgSQL_stmt *)new;
-                   }
-               ;
+                                               $$ = (PLpgSQL_stmt *)new;
+                                       }
+                               ;
 
-stmt_dynexecute        : K_EXECUTE lno expr_until_semi
-                       {
-                               PLpgSQL_stmt_dynexecute *new;
+stmt_dynexecute : K_EXECUTE lno expr_until_semi
+                                               {
+                                                               PLpgSQL_stmt_dynexecute *new;
 
-                       new = malloc(sizeof(PLpgSQL_stmt_dynexecute));
-                       new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;
-                       new->lineno   = $2;
-                       new->query    = $3;
+                                               new = malloc(sizeof(PLpgSQL_stmt_dynexecute));
+                                               new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;
+                                               new->lineno   = $2;
+                                               new->query        = $3;
 
-                       $$ = (PLpgSQL_stmt *)new;
-                       }
-               ;
+                                               $$ = (PLpgSQL_stmt *)new;
+                                               }
+                               ;
 
 execsql_start  : T_WORD
-                   { $$ = strdup(yytext); }
-               | T_ERROR
-                   { $$ = strdup(yytext); }
-               ;
-
-expr_until_semi        :
-                   { $$ = plpgsql_read_expression(';', ";"); }
-               ;
-
-expr_until_then        :
-                   { $$ = plpgsql_read_expression(K_THEN, "THEN"); }
-               ;
-
-expr_until_loop        :
-                   { $$ = plpgsql_read_expression(K_LOOP, "LOOP"); }
-               ;
-
-opt_label      :
-                   {
-                       plpgsql_ns_push(NULL);
-                       $$ = NULL;
-                   }
-               | '<' '<' opt_lblname '>' '>'
-                   {
-                       plpgsql_ns_push($3);
-                       $$ = $3;
-                   }
-               ;
+                                       { $$ = strdup(yytext); }
+                               | T_ERROR
+                                       { $$ = strdup(yytext); }
+                               ;
+
+expr_until_semi :
+                                       { $$ = plpgsql_read_expression(';', ";"); }
+                               ;
+
+expr_until_then :
+                                       { $$ = plpgsql_read_expression(K_THEN, "THEN"); }
+                               ;
+
+expr_until_loop :
+                                       { $$ = plpgsql_read_expression(K_LOOP, "LOOP"); }
+                               ;
+
+opt_label              :
+                                       {
+                                               plpgsql_ns_push(NULL);
+                                               $$ = NULL;
+                                       }
+                               | '<' '<' opt_lblname '>' '>'
+                                       {
+                                               plpgsql_ns_push($3);
+                                               $$ = $3;
+                                       }
+                               ;
 
 opt_exitlabel  :
-                   { $$ = NULL; }
-               | T_LABEL
-                   { $$ = strdup(yytext); }
-               ;
+                                       { $$ = NULL; }
+                               | T_LABEL
+                                       { $$ = strdup(yytext); }
+                               ;
 
 opt_exitcond   : ';'
-                   { $$ = NULL; }
-               | K_WHEN expr_until_semi
-                   { $$ = $2; }
-               ;
-
-opt_lblname    : T_WORD
-                   { $$ = strdup(yytext); }
-               ;
-
-lno            :
-                   {
-                       plpgsql_error_lineno = yylineno;
-                       $$ = yylineno;
-                   }
-               ;
+                                       { $$ = NULL; }
+                               | K_WHEN expr_until_semi
+                                       { $$ = $2; }
+                               ;
+
+opt_lblname            : T_WORD
+                                       { $$ = strdup(yytext); }
+                               ;
+
+lno                            :
+                                       {
+                                               plpgsql_error_lineno = yylineno;
+                                               $$ = yylineno;
+                                       }
+                               ;
 
 %%
 
@@ -1244,237 +1244,104 @@ lno           :
 PLpgSQL_expr *
 plpgsql_read_expression (int until, char *s)
 {
-    return read_sqlstmt(until, s, "SELECT ");
+       return read_sqlstmt(until, s, "SELECT ");
 }
 
 
 static PLpgSQL_expr *
 read_sqlstmt (int until, char *s, char *sqlstart)
 {
-    int                        tok;
-    int                        lno;
-    PLpgSQL_dstring    ds;
-    int                        nparams = 0;
-    int                        params[1024];
-    char               buf[32];
-    PLpgSQL_expr       *expr;
-
-    lno = yylineno;
-    plpgsql_dstring_init(&ds);
-    plpgsql_dstring_append(&ds, sqlstart);
-
-    while((tok = yylex()) != until) {
-       if (tok == ';') break;
-       if (plpgsql_SpaceScanned) {
-           plpgsql_dstring_append(&ds, " ");
-       }
-        switch (tok) {
-           case T_VARIABLE:
-               params[nparams] = yylval.var->varno;
-               sprintf(buf, " $%d ", ++nparams);
-               plpgsql_dstring_append(&ds, buf);
-               break;
-               
-           case T_RECFIELD:
-               params[nparams] = yylval.recfield->rfno;
-               sprintf(buf, " $%d ", ++nparams);
-               plpgsql_dstring_append(&ds, buf);
-               break;
-               
-           case T_TGARGV:
-               params[nparams] = yylval.trigarg->dno;
-               sprintf(buf, " $%d ", ++nparams);
-               plpgsql_dstring_append(&ds, buf);
-               break;
-               
-           default:
-               if (tok == 0) {
-                   plpgsql_error_lineno = lno;
-                   plpgsql_comperrinfo();
-                   elog(ERROR, "missing %s at end of SQL statement", s);
-               }
-               plpgsql_dstring_append(&ds, yytext);
-               break;
-        }
-    }
-
-    expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
-    expr->dtype                = PLPGSQL_DTYPE_EXPR;
-    expr->query                = strdup(plpgsql_dstring_get(&ds));
-    expr->plan         = NULL;
-    expr->nparams      = nparams;
-    while(nparams-- > 0) {
-        expr->params[nparams] = params[nparams];
-    }
-    plpgsql_dstring_free(&ds);
-    
-    return expr;
-}
-
-
-static PLpgSQL_stmt *
-make_select_stmt()
-{
-    int                        tok;
-    int                        lno;
-    PLpgSQL_dstring    ds;
-    int                        nparams = 0;
-    int                        params[1024];
-    char               buf[32];
-    PLpgSQL_expr       *expr;
-    PLpgSQL_row                *row = NULL;
-    PLpgSQL_rec                *rec = NULL;
-    PLpgSQL_stmt_select        *select;
-    int                        have_nexttok = 0;
-
-    lno = yylineno;
-    plpgsql_dstring_init(&ds);
-    plpgsql_dstring_append(&ds, "SELECT ");
-
-    while((tok = yylex()) != K_INTO) {
-       if (tok == ';') {
-           PLpgSQL_stmt_execsql        *execsql;
-
-           expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
-           expr->dtype         = PLPGSQL_DTYPE_EXPR;
-           expr->query         = strdup(plpgsql_dstring_get(&ds));
-           expr->plan          = NULL;
-           expr->nparams       = nparams;
-           while(nparams-- > 0) {
-               expr->params[nparams] = params[nparams];
-           }
-           plpgsql_dstring_free(&ds);
+       int                                     tok;
+       int                                     lno;
+       PLpgSQL_dstring         ds;
+       int                                     nparams = 0;
+       int                                     params[1024];
+       char                            buf[32];
+       PLpgSQL_expr            *expr;
 
-           execsql = malloc(sizeof(PLpgSQL_stmt_execsql));
-           execsql->cmd_type = PLPGSQL_STMT_EXECSQL;
-           execsql->sqlstmt  = expr;
+       lno = yylineno;
+       plpgsql_dstring_init(&ds);
+       plpgsql_dstring_append(&ds, sqlstart);
 
-           return (PLpgSQL_stmt *)execsql;
-       }
-
-       if (plpgsql_SpaceScanned) {
-           plpgsql_dstring_append(&ds, " ");
-       }
-        switch (tok) {
-           case T_VARIABLE:
-               params[nparams] = yylval.var->varno;
-               sprintf(buf, " $%d ", ++nparams);
-               plpgsql_dstring_append(&ds, buf);
-               break;
-               
-           case T_RECFIELD:
-               params[nparams] = yylval.recfield->rfno;
-               sprintf(buf, " $%d ", ++nparams);
-               plpgsql_dstring_append(&ds, buf);
-               break;
-               
-           case T_TGARGV:
-               params[nparams] = yylval.trigarg->dno;
-               sprintf(buf, " $%d ", ++nparams);
-               plpgsql_dstring_append(&ds, buf);
-               break;
-               
-           default:
-               if (tok == 0) {
-                   plpgsql_error_lineno = yylineno;
-                   plpgsql_comperrinfo();
-                   elog(ERROR, "unexpected end of file");
+       while((tok = yylex()) != until) {
+               if (tok == ';') break;
+               if (plpgsql_SpaceScanned) {
+                       plpgsql_dstring_append(&ds, " ");
                }
-               plpgsql_dstring_append(&ds, yytext);
-               break;
-        }
-    }
-
-    tok = yylex();
-    switch (tok) {
-        case T_ROW:
-           row = yylval.row;
-           break;
-
-        case T_RECORD:
-           rec = yylval.rec;
-           break;
-
-       case T_VARIABLE:
-       case T_RECFIELD:
-           {
-               PLpgSQL_var     *var;
-               PLpgSQL_recfield *recfield;
-               int             nfields = 1;
-               char            *fieldnames[1024];
-               int             varnos[1024];
-
                switch (tok) {
-                   case T_VARIABLE:
-                       var = yylval.var;
-                       fieldnames[0] = strdup(yytext);
-                       varnos[0]     = var->varno;
-                       break;
-                   
-                   case T_RECFIELD:
-                       recfield = yylval.recfield;
-                       fieldnames[0] = strdup(yytext);
-                       varnos[0]     = recfield->rfno;
-                       break;
-               }
-
-               while ((tok = yylex()) == ',') {
-                   tok = yylex();
-                   switch(tok) {
                        case T_VARIABLE:
-                           var = yylval.var;
-                           fieldnames[nfields] = strdup(yytext);
-                           varnos[nfields++]   = var->varno;
-                           break;
+                               params[nparams] = yylval.var->varno;
+                               sprintf(buf, " $%d ", ++nparams);
+                               plpgsql_dstring_append(&ds, buf);
+                               break;
 
                        case T_RECFIELD:
-                           recfield = yylval.recfield;
-                           fieldnames[0] = strdup(yytext);
-                           varnos[0]     = recfield->rfno;
-                           break;
+                               params[nparams] = yylval.recfield->rfno;
+                               sprintf(buf, " $%d ", ++nparams);
+                               plpgsql_dstring_append(&ds, buf);
+                               break;
+
+                       case T_TGARGV:
+                               params[nparams] = yylval.trigarg->dno;
+                               sprintf(buf, " $%d ", ++nparams);
+                               plpgsql_dstring_append(&ds, buf);
+                               break;
 
                        default:
-                           elog(ERROR, "plpgsql: %s is not a variable or record field", yytext);
-                   }
-               }
-               row = malloc(sizeof(PLpgSQL_row));
-               row->dtype = PLPGSQL_DTYPE_ROW;
-               row->refname = strdup("*internal*");
-               row->lineno = yylineno;
-               row->rowtypeclass = InvalidOid;
-               row->nfields = nfields;
-               row->fieldnames = malloc(sizeof(char *) * nfields);
-               row->varnos = malloc(sizeof(int) * nfields);
-               while (--nfields >= 0) {
-                   row->fieldnames[nfields] = fieldnames[nfields];
-                   row->varnos[nfields] = varnos[nfields];
+                               if (tok == 0) {
+                                       plpgsql_error_lineno = lno;
+                                       plpgsql_comperrinfo();
+                                       elog(ERROR, "missing %s at end of SQL statement", s);
+                               }
+                               plpgsql_dstring_append(&ds, yytext);
+                               break;
                }
+       }
 
-               plpgsql_adddatum((PLpgSQL_datum *)row);
+       expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
+       expr->dtype                     = PLPGSQL_DTYPE_EXPR;
+       expr->query                     = strdup(plpgsql_dstring_get(&ds));
+       expr->plan                      = NULL;
+       expr->nparams           = nparams;
+       while(nparams-- > 0) {
+               expr->params[nparams] = params[nparams];
+       }
+       plpgsql_dstring_free(&ds);
 
-               have_nexttok = 1;
-           }
-           break;
+       return expr;
+}
 
-        default:
-           {
-               if (plpgsql_SpaceScanned) {
-                   plpgsql_dstring_append(&ds, " ");
-               }
-               plpgsql_dstring_append(&ds, yytext);
 
-               while(1) {
-                   tok = yylex();
-                   if (tok == ';') {
-                       PLpgSQL_stmt_execsql    *execsql;
+static PLpgSQL_stmt *
+make_select_stmt()
+{
+       int                                     tok;
+       int                                     lno;
+       PLpgSQL_dstring         ds;
+       int                                     nparams = 0;
+       int                                     params[1024];
+       char                            buf[32];
+       PLpgSQL_expr            *expr;
+       PLpgSQL_row                     *row = NULL;
+       PLpgSQL_rec                     *rec = NULL;
+       PLpgSQL_stmt_select *select;
+       int                                     have_nexttok = 0;
+
+       lno = yylineno;
+       plpgsql_dstring_init(&ds);
+       plpgsql_dstring_append(&ds, "SELECT ");
+
+       while((tok = yylex()) != K_INTO) {
+               if (tok == ';') {
+                       PLpgSQL_stmt_execsql            *execsql;
 
                        expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
-                       expr->dtype             = PLPGSQL_DTYPE_EXPR;
-                       expr->query             = strdup(plpgsql_dstring_get(&ds));
-                       expr->plan              = NULL;
-                       expr->nparams   = nparams;
+                       expr->dtype                     = PLPGSQL_DTYPE_EXPR;
+                       expr->query                     = strdup(plpgsql_dstring_get(&ds));
+                       expr->plan                      = NULL;
+                       expr->nparams           = nparams;
                        while(nparams-- > 0) {
-                           expr->params[nparams] = params[nparams];
+                               expr->params[nparams] = params[nparams];
                        }
                        plpgsql_dstring_free(&ds);
 
@@ -1483,134 +1350,267 @@ make_select_stmt()
                        execsql->sqlstmt  = expr;
 
                        return (PLpgSQL_stmt *)execsql;
-                   }
+               }
 
-                   if (plpgsql_SpaceScanned) {
+               if (plpgsql_SpaceScanned) {
                        plpgsql_dstring_append(&ds, " ");
-                   }
-                   switch (tok) {
+               }
+               switch (tok) {
                        case T_VARIABLE:
-                           params[nparams] = yylval.var->varno;
-                           sprintf(buf, " $%d ", ++nparams);
-                           plpgsql_dstring_append(&ds, buf);
-                           break;
-                           
+                               params[nparams] = yylval.var->varno;
+                               sprintf(buf, " $%d ", ++nparams);
+                               plpgsql_dstring_append(&ds, buf);
+                               break;
+
                        case T_RECFIELD:
-                           params[nparams] = yylval.recfield->rfno;
-                           sprintf(buf, " $%d ", ++nparams);
-                           plpgsql_dstring_append(&ds, buf);
-                           break;
-                           
+                               params[nparams] = yylval.recfield->rfno;
+                               sprintf(buf, " $%d ", ++nparams);
+                               plpgsql_dstring_append(&ds, buf);
+                               break;
+
                        case T_TGARGV:
-                           params[nparams] = yylval.trigarg->dno;
-                           sprintf(buf, " $%d ", ++nparams);
-                           plpgsql_dstring_append(&ds, buf);
-                           break;
-                           
+                               params[nparams] = yylval.trigarg->dno;
+                               sprintf(buf, " $%d ", ++nparams);
+                               plpgsql_dstring_append(&ds, buf);
+                               break;
+
                        default:
-                           if (tok == 0) {
-                               plpgsql_error_lineno = yylineno;
-                               plpgsql_comperrinfo();
-                               elog(ERROR, "unexpected end of file");
-                           }
-                           plpgsql_dstring_append(&ds, yytext);
-                           break;
-                   }
+                               if (tok == 0) {
+                                       plpgsql_error_lineno = yylineno;
+                                       plpgsql_comperrinfo();
+                                       elog(ERROR, "unexpected end of file");
+                               }
+                               plpgsql_dstring_append(&ds, yytext);
+                               break;
                }
-           }
-    }
-
-    /************************************************************
-     * Eat up the rest of the statement after the target fields
-     ************************************************************/
-    while(1) {
-       if (!have_nexttok) {
-           tok = yylex();
-       }
-       have_nexttok = 0;
-       if (tok == ';') {
-           break;
        }
 
-       if (plpgsql_SpaceScanned) {
-           plpgsql_dstring_append(&ds, " ");
-       }
+       tok = yylex();
        switch (tok) {
-           case T_VARIABLE:
-               params[nparams] = yylval.var->varno;
-               sprintf(buf, " $%d ", ++nparams);
-               plpgsql_dstring_append(&ds, buf);
-               break;
-               
-           case T_RECFIELD:
-               params[nparams] = yylval.recfield->rfno;
-               sprintf(buf, " $%d ", ++nparams);
-               plpgsql_dstring_append(&ds, buf);
-               break;
-               
-           case T_TGARGV:
-               params[nparams] = yylval.trigarg->dno;
-               sprintf(buf, " $%d ", ++nparams);
-               plpgsql_dstring_append(&ds, buf);
-               break;
-               
-           default:
-               if (tok == 0) {
-                   plpgsql_error_lineno = yylineno;
-                   plpgsql_comperrinfo();
-                   elog(ERROR, "unexpected end of file");
+               case T_ROW:
+                       row = yylval.row;
+                       break;
+
+               case T_RECORD:
+                       rec = yylval.rec;
+                       break;
+
+               case T_VARIABLE:
+               case T_RECFIELD:
+                       {
+                               PLpgSQL_var             *var;
+                               PLpgSQL_recfield *recfield;
+                               int                             nfields = 1;
+                               char                    *fieldnames[1024];
+                               int                             varnos[1024];
+
+                               switch (tok) {
+                                       case T_VARIABLE:
+                                               var = yylval.var;
+                                               fieldnames[0] = strdup(yytext);
+                                               varnos[0]         = var->varno;
+                                               break;
+
+                                       case T_RECFIELD:
+                                               recfield = yylval.recfield;
+                                               fieldnames[0] = strdup(yytext);
+                                               varnos[0]         = recfield->rfno;
+                                               break;
+                               }
+
+                               while ((tok = yylex()) == ',') {
+                                       tok = yylex();
+                                       switch(tok) {
+                                               case T_VARIABLE:
+                                                       var = yylval.var;
+                                                       fieldnames[nfields] = strdup(yytext);
+                                                       varnos[nfields++]       = var->varno;
+                                                       break;
+
+                                               case T_RECFIELD:
+                                                       recfield = yylval.recfield;
+                                                       fieldnames[0] = strdup(yytext);
+                                                       varnos[0]         = recfield->rfno;
+                                                       break;
+
+                                               default:
+                                                       elog(ERROR, "plpgsql: %s is not a variable or record field", yytext);
+                                       }
+                               }
+                               row = malloc(sizeof(PLpgSQL_row));
+                               row->dtype = PLPGSQL_DTYPE_ROW;
+                               row->refname = strdup("*internal*");
+                               row->lineno = yylineno;
+                               row->rowtypeclass = InvalidOid;
+                               row->nfields = nfields;
+                               row->fieldnames = malloc(sizeof(char *) * nfields);
+                               row->varnos = malloc(sizeof(int) * nfields);
+                               while (--nfields >= 0) {
+                                       row->fieldnames[nfields] = fieldnames[nfields];
+                                       row->varnos[nfields] = varnos[nfields];
+                               }
+
+                               plpgsql_adddatum((PLpgSQL_datum *)row);
+
+                               have_nexttok = 1;
+                       }
+                       break;
+
+               default:
+                       {
+                               if (plpgsql_SpaceScanned) {
+                                       plpgsql_dstring_append(&ds, " ");
+                               }
+                               plpgsql_dstring_append(&ds, yytext);
+
+                               while(1) {
+                                       tok = yylex();
+                                       if (tok == ';') {
+                                               PLpgSQL_stmt_execsql    *execsql;
+
+                                               expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - 1);
+                                               expr->dtype                             = PLPGSQL_DTYPE_EXPR;
+                                               expr->query                             = strdup(plpgsql_dstring_get(&ds));
+                                               expr->plan                              = NULL;
+                                               expr->nparams   = nparams;
+                                               while(nparams-- > 0) {
+                                                       expr->params[nparams] = params[nparams];
+                                               }
+                                               plpgsql_dstring_free(&ds);
+
+                                               execsql = malloc(sizeof(PLpgSQL_stmt_execsql));
+                                               execsql->cmd_type = PLPGSQL_STMT_EXECSQL;
+                                               execsql->sqlstmt  = expr;
+
+                                               return (PLpgSQL_stmt *)execsql;
+                                       }
+
+                                       if (plpgsql_SpaceScanned) {
+                                               plpgsql_dstring_append(&ds, " ");
+                                       }
+                                       switch (tok) {
+                                               case T_VARIABLE:
+                                                       params[nparams] = yylval.var->varno;
+                                                       sprintf(buf, " $%d ", ++nparams);
+                                                       plpgsql_dstring_append(&ds, buf);
+                                                       break;
+
+                                               case T_RECFIELD:
+                                                       params[nparams] = yylval.recfield->rfno;
+                                                       sprintf(buf, " $%d ", ++nparams);
+                                                       plpgsql_dstring_append(&ds, buf);
+                                                       break;
+
+                                               case T_TGARGV:
+                                                       params[nparams] = yylval.trigarg->dno;
+                                                       sprintf(buf, " $%d ", ++nparams);
+                                                       plpgsql_dstring_append(&ds, buf);
+                                                       break;
+
+                                               default:
+                                                       if (tok == 0) {
+                                                               plpgsql_error_lineno = yylineno;
+                                                               plpgsql_comperrinfo();
+                                                               elog(ERROR, "unexpected end of file");
+                                                       }
+                                                       plpgsql_dstring_append(&ds, yytext);
+                                                       break;
+                                       }
+                               }
+                       }
+       }
+
+       /************************************************************
+        * Eat up the rest of the statement after the target fields
+        ************************************************************/
+       while(1) {
+               if (!have_nexttok) {
+                       tok = yylex();
+               }
+               have_nexttok = 0;
+               if (tok == ';') {
+                       break;
+               }
+
+               if (plpgsql_SpaceScanned) {
+                       plpgsql_dstring_append(&ds, " ");
+               }
+               switch (tok) {
+                       case T_VARIABLE:
+                               params[nparams] = yylval.var->varno;
+                               sprintf(buf, " $%d ", ++nparams);
+                               plpgsql_dstring_append(&ds, buf);
+                               break;
+
+                       case T_RECFIELD:
+                               params[nparams] = yylval.recfield->rfno;
+                               sprintf(buf, " $%d ", ++nparams);
+                               plpgsql_dstring_append(&ds, buf);
+                               break;
+
+                       case T_TGARGV:
+                               params[nparams] = yylval.trigarg->dno;
+                               sprintf(buf, " $%d ", ++nparams);
+                               plpgsql_dstring_append(&ds, buf);
+                               break;
+
+                       default:
+                               if (tok == 0) {
+                                       plpgsql_error_lineno = yylineno;
+                                       plpgsql_comperrinfo();
+                                       elog(ERROR, "unexpected end of file");
+                               }
+                               plpgsql_dstring_append(&ds, yytext);
+                               break;
                }
-               plpgsql_dstring_append(&ds, yytext);
-               break;
        }
-    }
-
-    expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * (nparams - 1));
-    expr->dtype                = PLPGSQL_DTYPE_EXPR;
-    expr->query                = strdup(plpgsql_dstring_get(&ds));
-    expr->plan         = NULL;
-    expr->nparams      = nparams;
-    while(nparams-- > 0) {
-        expr->params[nparams] = params[nparams];
-    }
-    plpgsql_dstring_free(&ds);
-
-    select = malloc(sizeof(PLpgSQL_stmt_select));
-    memset(select, 0, sizeof(PLpgSQL_stmt_select));
-    select->cmd_type = PLPGSQL_STMT_SELECT;
-    select->rec      = rec;
-    select->row      = row;
-    select->query    = expr;
-    
-    return (PLpgSQL_stmt *)select;
+
+       expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * (nparams - 1));
+       expr->dtype                     = PLPGSQL_DTYPE_EXPR;
+       expr->query                     = strdup(plpgsql_dstring_get(&ds));
+       expr->plan                      = NULL;
+       expr->nparams           = nparams;
+       while(nparams-- > 0) {
+               expr->params[nparams] = params[nparams];
+       }
+       plpgsql_dstring_free(&ds);
+
+       select = malloc(sizeof(PLpgSQL_stmt_select));
+       memset(select, 0, sizeof(PLpgSQL_stmt_select));
+       select->cmd_type = PLPGSQL_STMT_SELECT;
+       select->rec              = rec;
+       select->row              = row;
+       select->query    = expr;
+
+       return (PLpgSQL_stmt *)select;
 }
 
 
 static PLpgSQL_expr *
 make_tupret_expr(PLpgSQL_row *row)
 {
-    PLpgSQL_dstring    ds;
-    PLpgSQL_expr       *expr;
-    int                        i;
-    char               buf[16];
-
-    expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * (row->nfields - 1));
-    expr->dtype                = PLPGSQL_DTYPE_EXPR;
-
-    plpgsql_dstring_init(&ds);
-    plpgsql_dstring_append(&ds, "SELECT ");
-
-    for (i = 0; i < row->nfields; i++) {
-        sprintf(buf, "%s$%d", (i > 0) ? "," : "", i + 1);
-       plpgsql_dstring_append(&ds, buf);
-       expr->params[i] = row->varnos[i];
-    }
-
-    expr->query         = strdup(plpgsql_dstring_get(&ds));
-    expr->plan          = NULL;
-    expr->plan_argtypes = NULL;
-    expr->nparams       = row->nfields;
-
-    plpgsql_dstring_free(&ds);
-    return expr;
+       PLpgSQL_dstring         ds;
+       PLpgSQL_expr            *expr;
+       int                                     i;
+       char                            buf[16];
+
+       expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * (row->nfields - 1));
+       expr->dtype                     = PLPGSQL_DTYPE_EXPR;
+
+       plpgsql_dstring_init(&ds);
+       plpgsql_dstring_append(&ds, "SELECT ");
+
+       for (i = 0; i < row->nfields; i++) {
+               sprintf(buf, "%s$%d", (i > 0) ? "," : "", i + 1);
+               plpgsql_dstring_append(&ds, buf);
+               expr->params[i] = row->varnos[i];
+       }
+
+       expr->query                     = strdup(plpgsql_dstring_get(&ds));
+       expr->plan                      = NULL;
+       expr->plan_argtypes = NULL;
+       expr->nparams           = row->nfields;
+
+       plpgsql_dstring_free(&ds);
+       return expr;
 }