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

index ed1704276e9deb8fd790d0eb818b79f9dd4e3a70..80580de50101e53d7ab989a5daf4e15eca19cc92 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     decl_sect
-%type     decl_varname
-%type     decl_renname
+%type  decl_sect
+%type  decl_varname
+%type         decl_renname
 %type    decl_const, decl_notnull, decl_atttypmod, decl_atttypmodval
 %type    decl_defval
 %type   decl_datatype, decl_dtypename
-%type     decl_rowtype
+%type         decl_rowtype
 %type  decl_aliasitem
-%type     decl_stmts, decl_stmt
+%type         decl_stmts, decl_stmt
 
 %type    expr_until_semi, expr_until_then, expr_until_loop
 %type    opt_exitcond
 
 %type    assign_var
-%type     fori_var
-%type     fori_varname
-%type     fori_lower
-%type     fors_target
+%type         fori_var
+%type  fori_varname
+%type  fori_lower
+%type         fors_target
 
-%type     opt_lblname, opt_label
-%type     opt_exitlabel
-%type     execsql_start
+%type         opt_lblname, opt_label
+%type         opt_exitlabel
+%type         execsql_start
 
 %type   proc_sect, proc_stmts, stmt_else, loop_body
 %type    proc_stmt, pl_block
@@ -117,16 +117,16 @@ static    PLpgSQL_expr    *make_tupret_expr(PLpgSQL_row *row);
 
 %type  raise_params
 %type    raise_level, raise_param
-%type     raise_msg
+%type         raise_msg
 
 %type  getdiag_items, getdiag_targets
 %type    getdiag_item, getdiag_target
 
 %type    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;
 }