LCOV - code coverage report
Current view: top level - src/pl/plpgsql/src - pl_gram.y (source / functions) Hit Total Coverage
Test: PostgreSQL 15devel Lines: 1203 1374 87.6 %
Date: 2021-09-17 16:07:28 Functions: 26 29 89.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : %{
       2             : /*-------------------------------------------------------------------------
       3             :  *
       4             :  * pl_gram.y            - Parser for the PL/pgSQL procedural language
       5             :  *
       6             :  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/pl/plpgsql/src/pl_gram.y
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : 
      16             : #include "postgres.h"
      17             : 
      18             : #include "catalog/namespace.h"
      19             : #include "catalog/pg_proc.h"
      20             : #include "catalog/pg_type.h"
      21             : #include "parser/parser.h"
      22             : #include "parser/parse_type.h"
      23             : #include "parser/scanner.h"
      24             : #include "parser/scansup.h"
      25             : #include "utils/builtins.h"
      26             : 
      27             : #include "plpgsql.h"
      28             : 
      29             : 
      30             : /* Location tracking support --- simpler than bison's default */
      31             : #define YYLLOC_DEFAULT(Current, Rhs, N) \
      32             :     do { \
      33             :         if (N) \
      34             :             (Current) = (Rhs)[1]; \
      35             :         else \
      36             :             (Current) = (Rhs)[0]; \
      37             :     } while (0)
      38             : 
      39             : /*
      40             :  * Bison doesn't allocate anything that needs to live across parser calls,
      41             :  * so we can easily have it use palloc instead of malloc.  This prevents
      42             :  * memory leaks if we error out during parsing.  Note this only works with
      43             :  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
      44             :  * if possible, so there's not really much problem anyhow, at least if
      45             :  * you're building with gcc.
      46             :  */
      47             : #define YYMALLOC palloc
      48             : #define YYFREE   pfree
      49             : 
      50             : 
      51             : typedef struct
      52             : {
      53             :     int         location;
      54             : } sql_error_callback_arg;
      55             : 
      56             : #define parser_errposition(pos)  plpgsql_scanner_errposition(pos)
      57             : 
      58             : union YYSTYPE;                  /* need forward reference for tok_is_keyword */
      59             : 
      60             : static  bool            tok_is_keyword(int token, union YYSTYPE *lval,
      61             :                                        int kw_token, const char *kw_str);
      62             : static  void            word_is_not_variable(PLword *word, int location);
      63             : static  void            cword_is_not_variable(PLcword *cword, int location);
      64             : static  void            current_token_is_not_variable(int tok);
      65             : static  PLpgSQL_expr    *read_sql_construct(int until,
      66             :                                             int until2,
      67             :                                             int until3,
      68             :                                             const char *expected,
      69             :                                             RawParseMode parsemode,
      70             :                                             bool isexpression,
      71             :                                             bool valid_sql,
      72             :                                             bool trim,
      73             :                                             int *startloc,
      74             :                                             int *endtoken);
      75             : static  PLpgSQL_expr    *read_sql_expression(int until,
      76             :                                              const char *expected);
      77             : static  PLpgSQL_expr    *read_sql_expression2(int until, int until2,
      78             :                                               const char *expected,
      79             :                                               int *endtoken);
      80             : static  PLpgSQL_expr    *read_sql_stmt(void);
      81             : static  PLpgSQL_type    *read_datatype(int tok);
      82             : static  PLpgSQL_stmt    *make_execsql_stmt(int firsttoken, int location);
      83             : static  PLpgSQL_stmt_fetch *read_fetch_direction(void);
      84             : static  void             complete_direction(PLpgSQL_stmt_fetch *fetch,
      85             :                                             bool *check_FROM);
      86             : static  PLpgSQL_stmt    *make_return_stmt(int location);
      87             : static  PLpgSQL_stmt    *make_return_next_stmt(int location);
      88             : static  PLpgSQL_stmt    *make_return_query_stmt(int location);
      89             : static  PLpgSQL_stmt    *make_case(int location, PLpgSQL_expr *t_expr,
      90             :                                    List *case_when_list, List *else_stmts);
      91             : static  char            *NameOfDatum(PLwdatum *wdatum);
      92             : static  void             check_assignable(PLpgSQL_datum *datum, int location);
      93             : static  void             read_into_target(PLpgSQL_variable **target,
      94             :                                           bool *strict);
      95             : static  PLpgSQL_row     *read_into_scalar_list(char *initial_name,
      96             :                                                PLpgSQL_datum *initial_datum,
      97             :                                                int initial_location);
      98             : static  PLpgSQL_row     *make_scalar_list1(char *initial_name,
      99             :                                            PLpgSQL_datum *initial_datum,
     100             :                                            int lineno, int location);
     101             : static  void             check_sql_expr(const char *stmt,
     102             :                                         RawParseMode parseMode, int location);
     103             : static  void             plpgsql_sql_error_callback(void *arg);
     104             : static  PLpgSQL_type    *parse_datatype(const char *string, int location);
     105             : static  void             check_labels(const char *start_label,
     106             :                                       const char *end_label,
     107             :                                       int end_location);
     108             : static  PLpgSQL_expr    *read_cursor_args(PLpgSQL_var *cursor,
     109             :                                           int until);
     110             : static  List            *read_raise_options(void);
     111             : static  void            check_raise_parameters(PLpgSQL_stmt_raise *stmt);
     112             : 
     113             : %}
     114             : 
     115             : %expect 0
     116             : %name-prefix="plpgsql_yy"
     117             : %locations
     118             : 
     119             : %union {
     120             :         core_YYSTYPE            core_yystype;
     121             :         /* these fields must match core_YYSTYPE: */
     122             :         int                     ival;
     123             :         char                    *str;
     124             :         const char              *keyword;
     125             : 
     126             :         PLword                  word;
     127             :         PLcword                 cword;
     128             :         PLwdatum                wdatum;
     129             :         bool                    boolean;
     130             :         Oid                     oid;
     131             :         struct
     132             :         {
     133             :             char *name;
     134             :             int  lineno;
     135             :         }                       varname;
     136             :         struct
     137             :         {
     138             :             char *name;
     139             :             int  lineno;
     140             :             PLpgSQL_datum   *scalar;
     141             :             PLpgSQL_datum   *row;
     142             :         }                       forvariable;
     143             :         struct
     144             :         {
     145             :             char *label;
     146             :             int  n_initvars;
     147             :             int  *initvarnos;
     148             :         }                       declhdr;
     149             :         struct
     150             :         {
     151             :             List *stmts;
     152             :             char *end_label;
     153             :             int   end_label_location;
     154             :         }                       loop_body;
     155             :         List                    *list;
     156             :         PLpgSQL_type            *dtype;
     157             :         PLpgSQL_datum           *datum;
     158             :         PLpgSQL_var             *var;
     159             :         PLpgSQL_expr            *expr;
     160             :         PLpgSQL_stmt            *stmt;
     161             :         PLpgSQL_condition       *condition;
     162             :         PLpgSQL_exception       *exception;
     163             :         PLpgSQL_exception_block *exception_block;
     164             :         PLpgSQL_nsitem          *nsitem;
     165             :         PLpgSQL_diag_item       *diagitem;
     166             :         PLpgSQL_stmt_fetch      *fetch;
     167             :         PLpgSQL_case_when       *casewhen;
     168             : }
     169             : 
     170             : %type <declhdr> decl_sect
     171             : %type <varname> decl_varname
     172             : %type <boolean>   decl_const decl_notnull exit_type
     173             : %type <expr>  decl_defval decl_cursor_query
     174             : %type <dtype> decl_datatype
     175             : %type <oid>       decl_collate
     176             : %type <datum> decl_cursor_args
     177             : %type <list>  decl_cursor_arglist
     178             : %type <nsitem>    decl_aliasitem
     179             : 
     180             : %type <expr>  expr_until_semi
     181             : %type <expr>  expr_until_then expr_until_loop opt_expr_until_when
     182             : %type <expr>  opt_exitcond
     183             : 
     184             : %type <var>       cursor_variable
     185             : %type <datum> decl_cursor_arg
     186             : %type <forvariable>   for_variable
     187             : %type <ival>  foreach_slice
     188             : %type <stmt>  for_control
     189             : 
     190             : %type <str>       any_identifier opt_block_label opt_loop_label opt_label
     191             : %type <str>       option_value
     192             : 
     193             : %type <list>  proc_sect stmt_elsifs stmt_else
     194             : %type <loop_body> loop_body
     195             : %type <stmt>  proc_stmt pl_block
     196             : %type <stmt>  stmt_assign stmt_if stmt_loop stmt_while stmt_exit
     197             : %type <stmt>  stmt_return stmt_raise stmt_assert stmt_execsql
     198             : %type <stmt>  stmt_dynexecute stmt_for stmt_perform stmt_call stmt_getdiag
     199             : %type <stmt>  stmt_open stmt_fetch stmt_move stmt_close stmt_null
     200             : %type <stmt>  stmt_commit stmt_rollback
     201             : %type <stmt>  stmt_case stmt_foreach_a
     202             : 
     203             : %type <list>  proc_exceptions
     204             : %type <exception_block> exception_sect
     205             : %type <exception> proc_exception
     206             : %type <condition> proc_conditions proc_condition
     207             : 
     208             : %type <casewhen>  case_when
     209             : %type <list>  case_when_list opt_case_else
     210             : 
     211             : %type <boolean>   getdiag_area_opt
     212             : %type <list>  getdiag_list
     213             : %type <diagitem> getdiag_list_item
     214             : %type <datum> getdiag_target
     215             : %type <ival>  getdiag_item
     216             : 
     217             : %type <ival>  opt_scrollable
     218             : %type <fetch> opt_fetch_direction
     219             : 
     220             : %type <ival>  opt_transaction_chain
     221             : 
     222             : %type <keyword>   unreserved_keyword
     223             : 
     224             : 
     225             : /*
     226             :  * Basic non-keyword token types.  These are hard-wired into the core lexer.
     227             :  * They must be listed first so that their numeric codes do not depend on
     228             :  * the set of keywords.  Keep this list in sync with backend/parser/gram.y!
     229             :  *
     230             :  * Some of these are not directly referenced in this file, but they must be
     231             :  * here anyway.
     232             :  */
     233             : %token <str>  IDENT UIDENT FCONST SCONST USCONST BCONST XCONST Op
     234             : %token <ival> ICONST PARAM
     235             : %token          TYPECAST DOT_DOT COLON_EQUALS EQUALS_GREATER
     236             : %token          LESS_EQUALS GREATER_EQUALS NOT_EQUALS
     237             : 
     238             : /*
     239             :  * Other tokens recognized by plpgsql's lexer interface layer (pl_scanner.c).
     240             :  */
     241             : %token <word>     T_WORD      /* unrecognized simple identifier */
     242             : %token <cword>        T_CWORD     /* unrecognized composite identifier */
     243             : %token <wdatum>       T_DATUM     /* a VAR, ROW, REC, or RECFIELD variable */
     244             : %token              LESS_LESS
     245             : %token              GREATER_GREATER
     246             : 
     247             : /*
     248             :  * Keyword tokens.  Some of these are reserved and some are not;
     249             :  * see pl_scanner.c for info.  Be sure unreserved keywords are listed
     250             :  * in the "unreserved_keyword" production below.
     251             :  */
     252             : %token <keyword>  K_ABSOLUTE
     253             : %token <keyword>  K_ALIAS
     254             : %token <keyword>  K_ALL
     255             : %token <keyword>  K_AND
     256             : %token <keyword>  K_ARRAY
     257             : %token <keyword>  K_ASSERT
     258             : %token <keyword>  K_BACKWARD
     259             : %token <keyword>  K_BEGIN
     260             : %token <keyword>  K_BY
     261             : %token <keyword>  K_CALL
     262             : %token <keyword>  K_CASE
     263             : %token <keyword>  K_CHAIN
     264             : %token <keyword>  K_CLOSE
     265             : %token <keyword>  K_COLLATE
     266             : %token <keyword>  K_COLUMN
     267             : %token <keyword>  K_COLUMN_NAME
     268             : %token <keyword>  K_COMMIT
     269             : %token <keyword>  K_CONSTANT
     270             : %token <keyword>  K_CONSTRAINT
     271             : %token <keyword>  K_CONSTRAINT_NAME
     272             : %token <keyword>  K_CONTINUE
     273             : %token <keyword>  K_CURRENT
     274             : %token <keyword>  K_CURSOR
     275             : %token <keyword>  K_DATATYPE
     276             : %token <keyword>  K_DEBUG
     277             : %token <keyword>  K_DECLARE
     278             : %token <keyword>  K_DEFAULT
     279             : %token <keyword>  K_DETAIL
     280             : %token <keyword>  K_DIAGNOSTICS
     281             : %token <keyword>  K_DO
     282             : %token <keyword>  K_DUMP
     283             : %token <keyword>  K_ELSE
     284             : %token <keyword>  K_ELSIF
     285             : %token <keyword>  K_END
     286             : %token <keyword>  K_ERRCODE
     287             : %token <keyword>  K_ERROR
     288             : %token <keyword>  K_EXCEPTION
     289             : %token <keyword>  K_EXECUTE
     290             : %token <keyword>  K_EXIT
     291             : %token <keyword>  K_FETCH
     292             : %token <keyword>  K_FIRST
     293             : %token <keyword>  K_FOR
     294             : %token <keyword>  K_FOREACH
     295             : %token <keyword>  K_FORWARD
     296             : %token <keyword>  K_FROM
     297             : %token <keyword>  K_GET
     298             : %token <keyword>  K_HINT
     299             : %token <keyword>  K_IF
     300             : %token <keyword>  K_IMPORT
     301             : %token <keyword>  K_IN
     302             : %token <keyword>  K_INFO
     303             : %token <keyword>  K_INSERT
     304             : %token <keyword>  K_INTO
     305             : %token <keyword>  K_IS
     306             : %token <keyword>  K_LAST
     307             : %token <keyword>  K_LOG
     308             : %token <keyword>  K_LOOP
     309             : %token <keyword>  K_MESSAGE
     310             : %token <keyword>  K_MESSAGE_TEXT
     311             : %token <keyword>  K_MOVE
     312             : %token <keyword>  K_NEXT
     313             : %token <keyword>  K_NO
     314             : %token <keyword>  K_NOT
     315             : %token <keyword>  K_NOTICE
     316             : %token <keyword>  K_NULL
     317             : %token <keyword>  K_OPEN
     318             : %token <keyword>  K_OPTION
     319             : %token <keyword>  K_OR
     320             : %token <keyword>  K_PERFORM
     321             : %token <keyword>  K_PG_CONTEXT
     322             : %token <keyword>  K_PG_DATATYPE_NAME
     323             : %token <keyword>  K_PG_EXCEPTION_CONTEXT
     324             : %token <keyword>  K_PG_EXCEPTION_DETAIL
     325             : %token <keyword>  K_PG_EXCEPTION_HINT
     326             : %token <keyword>  K_PRINT_STRICT_PARAMS
     327             : %token <keyword>  K_PRIOR
     328             : %token <keyword>  K_QUERY
     329             : %token <keyword>  K_RAISE
     330             : %token <keyword>  K_RELATIVE
     331             : %token <keyword>  K_RETURN
     332             : %token <keyword>  K_RETURNED_SQLSTATE
     333             : %token <keyword>  K_REVERSE
     334             : %token <keyword>  K_ROLLBACK
     335             : %token <keyword>  K_ROW_COUNT
     336             : %token <keyword>  K_ROWTYPE
     337             : %token <keyword>  K_SCHEMA
     338             : %token <keyword>  K_SCHEMA_NAME
     339             : %token <keyword>  K_SCROLL
     340             : %token <keyword>  K_SLICE
     341             : %token <keyword>  K_SQLSTATE
     342             : %token <keyword>  K_STACKED
     343             : %token <keyword>  K_STRICT
     344             : %token <keyword>  K_TABLE
     345             : %token <keyword>  K_TABLE_NAME
     346             : %token <keyword>  K_THEN
     347             : %token <keyword>  K_TO
     348             : %token <keyword>  K_TYPE
     349             : %token <keyword>  K_USE_COLUMN
     350             : %token <keyword>  K_USE_VARIABLE
     351             : %token <keyword>  K_USING
     352             : %token <keyword>  K_VARIABLE_CONFLICT
     353             : %token <keyword>  K_WARNING
     354             : %token <keyword>  K_WHEN
     355             : %token <keyword>  K_WHILE
     356             : 
     357             : %%
     358             : 
     359             : pl_function     : comp_options pl_block opt_semi
     360             :                     {
     361        4988 :                         plpgsql_parse_result = (PLpgSQL_stmt_block *) $2;
     362             :                     }
     363             :                 ;
     364             : 
     365             : comp_options    :
     366             :                 | comp_options comp_option
     367             :                 ;
     368             : 
     369             : comp_option     : '#' K_OPTION K_DUMP
     370             :                     {
     371           0 :                         plpgsql_DumpExecTree = true;
     372             :                     }
     373             :                 | '#' K_PRINT_STRICT_PARAMS option_value
     374             :                     {
     375           8 :                         if (strcmp($3, "on") == 0)
     376           4 :                             plpgsql_curr_compile->print_strict_params = true;
     377           4 :                         else if (strcmp($3, "off") == 0)
     378           4 :                             plpgsql_curr_compile->print_strict_params = false;
     379             :                         else
     380           0 :                             elog(ERROR, "unrecognized print_strict_params option %s", $3);
     381             :                     }
     382             :                 | '#' K_VARIABLE_CONFLICT K_ERROR
     383             :                     {
     384           0 :                         plpgsql_curr_compile->resolve_option = PLPGSQL_RESOLVE_ERROR;
     385             :                     }
     386             :                 | '#' K_VARIABLE_CONFLICT K_USE_VARIABLE
     387             :                     {
     388           4 :                         plpgsql_curr_compile->resolve_option = PLPGSQL_RESOLVE_VARIABLE;
     389             :                     }
     390             :                 | '#' K_VARIABLE_CONFLICT K_USE_COLUMN
     391             :                     {
     392           4 :                         plpgsql_curr_compile->resolve_option = PLPGSQL_RESOLVE_COLUMN;
     393             :                     }
     394             :                 ;
     395             : 
     396             : option_value : T_WORD
     397             :                 {
     398           8 :                     $$ = $1.ident;
     399             :                 }
     400             :              | unreserved_keyword
     401             :                 {
     402           0 :                     $$ = pstrdup($1);
     403             :                 }
     404             : 
     405             : opt_semi        :
     406             :                 | ';'
     407             :                 ;
     408             : 
     409             : pl_block        : decl_sect K_BEGIN proc_sect exception_sect K_END opt_label
     410             :                     {
     411             :                         PLpgSQL_stmt_block *new;
     412             : 
     413        5142 :                         new = palloc0(sizeof(PLpgSQL_stmt_block));
     414             : 
     415        5142 :                         new->cmd_type    = PLPGSQL_STMT_BLOCK;
     416        5142 :                         new->lineno      = plpgsql_location_to_lineno(@2);
     417        5142 :                         new->stmtid      = ++plpgsql_curr_compile->nstatements;
     418        5142 :                         new->label       = $1.label;
     419        5142 :                         new->n_initvars = $1.n_initvars;
     420        5142 :                         new->initvarnos = $1.initvarnos;
     421        5142 :                         new->body        = $3;
     422        5142 :                         new->exceptions  = $4;
     423             : 
     424        5142 :                         check_labels($1.label, $6, @6);
     425        5142 :                         plpgsql_ns_pop();
     426             : 
     427        5142 :                         $$ = (PLpgSQL_stmt *)new;
     428             :                     }
     429             :                 ;
     430             : 
     431             : 
     432             : decl_sect       : opt_block_label
     433             :                     {
     434             :                         /* done with decls, so resume identifier lookup */
     435        2940 :                         plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
     436        2940 :                         $$.label      = $1;
     437        2940 :                         $$.n_initvars = 0;
     438        2940 :                         $$.initvarnos = NULL;
     439             :                     }
     440             :                 | opt_block_label decl_start
     441             :                     {
     442           4 :                         plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
     443           4 :                         $$.label      = $1;
     444           4 :                         $$.n_initvars = 0;
     445           4 :                         $$.initvarnos = NULL;
     446             :                     }
     447             :                 | opt_block_label decl_start decl_stmts
     448             :                     {
     449        2298 :                         plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
     450        2298 :                         $$.label      = $1;
     451             :                         /* Remember variables declared in decl_stmts */
     452        2298 :                         $$.n_initvars = plpgsql_add_initdatums(&($$.initvarnos));
     453             :                     }
     454             :                 ;
     455             : 
     456             : decl_start      : K_DECLARE
     457             :                     {
     458             :                         /* Forget any variables created before block */
     459        2314 :                         plpgsql_add_initdatums(NULL);
     460             :                         /*
     461             :                          * Disable scanner lookup of identifiers while
     462             :                          * we process the decl_stmts
     463             :                          */
     464        2314 :                         plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_DECLARE;
     465             :                     }
     466             :                 ;
     467             : 
     468             : decl_stmts      : decl_stmts decl_stmt
     469             :                 | decl_stmt
     470             :                 ;
     471             : 
     472             : decl_stmt       : decl_statement
     473             :                 | K_DECLARE
     474             :                     {
     475             :                         /* We allow useless extra DECLAREs */
     476             :                     }
     477             :                 | LESS_LESS any_identifier GREATER_GREATER
     478             :                     {
     479             :                         /*
     480             :                          * Throw a helpful error if user tries to put block
     481             :                          * label just before BEGIN, instead of before DECLARE.
     482             :                          */
     483           0 :                         ereport(ERROR,
     484             :                                 (errcode(ERRCODE_SYNTAX_ERROR),
     485             :                                  errmsg("block label must be placed before DECLARE, not after"),
     486             :                                  parser_errposition(@1)));
     487             :                     }
     488             :                 ;
     489             : 
     490             : decl_statement  : decl_varname decl_const decl_datatype decl_collate decl_notnull decl_defval
     491             :                     {
     492             :                         PLpgSQL_variable    *var;
     493             : 
     494             :                         /*
     495             :                          * If a collation is supplied, insert it into the
     496             :                          * datatype.  We assume decl_datatype always returns
     497             :                          * a freshly built struct not shared with other
     498             :                          * variables.
     499             :                          */
     500        4014 :                         if (OidIsValid($4))
     501             :                         {
     502           0 :                             if (!OidIsValid($3->collation))
     503           0 :                                 ereport(ERROR,
     504             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     505             :                                          errmsg("collations are not supported by type %s",
     506             :                                                 format_type_be($3->typoid)),
     507             :                                          parser_errposition(@4)));
     508           0 :                             $3->collation = $4;
     509             :                         }
     510             : 
     511        4014 :                         var = plpgsql_build_variable($1.name, $1.lineno,
     512        4014 :                                                      $3, true);
     513        4014 :                         var->isconst = $2;
     514        4014 :                         var->notnull = $5;
     515        4014 :                         var->default_val = $6;
     516             : 
     517             :                         /*
     518             :                          * The combination of NOT NULL without an initializer
     519             :                          * can't work, so let's reject it at compile time.
     520             :                          */
     521        4014 :                         if (var->notnull && var->default_val == NULL)
     522           6 :                             ereport(ERROR,
     523             :                                     (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     524             :                                      errmsg("variable \"%s\" must have a default value, since it's declared NOT NULL",
     525             :                                             var->refname),
     526             :                                      parser_errposition(@5)));
     527             :                     }
     528             :                 | decl_varname K_ALIAS K_FOR decl_aliasitem ';'
     529             :                     {
     530          56 :                         plpgsql_ns_additem($4->itemtype,
     531          56 :                                            $4->itemno, $1.name);
     532             :                     }
     533             :                 | decl_varname opt_scrollable K_CURSOR
     534          74 :                     { plpgsql_ns_push($1.name, PLPGSQL_LABEL_OTHER); }
     535             :                   decl_cursor_args decl_is_for decl_cursor_query
     536          74 :                     {
     537             :                         PLpgSQL_var *new;
     538             :                         PLpgSQL_expr *curname_def;
     539             :                         char        buf[NAMEDATALEN * 2 + 64];
     540             :                         char        *cp1;
     541             :                         char        *cp2;
     542             : 
     543             :                         /* pop local namespace for cursor args */
     544          74 :                         plpgsql_ns_pop();
     545             : 
     546             :                         new = (PLpgSQL_var *)
     547          74 :                             plpgsql_build_variable($1.name, $1.lineno,
     548             :                                                    plpgsql_build_datatype(REFCURSOROID,
     549             :                                                                           -1,
     550             :                                                                           InvalidOid,
     551             :                                                                           NULL),
     552             :                                                    true);
     553             : 
     554          74 :                         curname_def = palloc0(sizeof(PLpgSQL_expr));
     555             : 
     556             :                         /* Note: refname has been truncated to NAMEDATALEN */
     557          74 :                         cp1 = new->refname;
     558          74 :                         cp2 = buf;
     559             :                         /*
     560             :                          * Don't trust standard_conforming_strings here;
     561             :                          * it might change before we use the string.
     562             :                          */
     563          74 :                         if (strchr(cp1, '\\') != NULL)
     564           0 :                             *cp2++ = ESCAPE_STRING_SYNTAX;
     565          74 :                         *cp2++ = '\'';
     566         204 :                         while (*cp1)
     567             :                         {
     568         130 :                             if (SQL_STR_DOUBLE(*cp1, true))
     569           0 :                                 *cp2++ = *cp1;
     570         130 :                             *cp2++ = *cp1++;
     571             :                         }
     572          74 :                         strcpy(cp2, "'::pg_catalog.refcursor");
     573          74 :                         curname_def->query = pstrdup(buf);
     574          74 :                         curname_def->parseMode = RAW_PARSE_PLPGSQL_EXPR;
     575          74 :                         new->default_val = curname_def;
     576             : 
     577          74 :                         new->cursor_explicit_expr = $7;
     578          74 :                         if ($5 == NULL)
     579          26 :                             new->cursor_explicit_argrow = -1;
     580             :                         else
     581          48 :                             new->cursor_explicit_argrow = $5->dno;
     582          74 :                         new->cursor_options = CURSOR_OPT_FAST_PLAN | $2;
     583             :                     }
     584             :                 ;
     585             : 
     586             : opt_scrollable :
     587             :                     {
     588          66 :                         $$ = 0;
     589             :                     }
     590             :                 | K_NO K_SCROLL
     591             :                     {
     592           4 :                         $$ = CURSOR_OPT_NO_SCROLL;
     593             :                     }
     594             :                 | K_SCROLL
     595             :                     {
     596           4 :                         $$ = CURSOR_OPT_SCROLL;
     597             :                     }
     598             :                 ;
     599             : 
     600             : decl_cursor_query :
     601             :                     {
     602          74 :                         $$ = read_sql_stmt();
     603             :                     }
     604             :                 ;
     605             : 
     606             : decl_cursor_args :
     607             :                     {
     608          26 :                         $$ = NULL;
     609             :                     }
     610             :                 | '(' decl_cursor_arglist ')'
     611             :                     {
     612             :                         PLpgSQL_row *new;
     613             :                         int i;
     614             :                         ListCell *l;
     615             : 
     616          48 :                         new = palloc0(sizeof(PLpgSQL_row));
     617          48 :                         new->dtype = PLPGSQL_DTYPE_ROW;
     618          48 :                         new->refname = "(unnamed row)";
     619          48 :                         new->lineno = plpgsql_location_to_lineno(@1);
     620          48 :                         new->rowtupdesc = NULL;
     621          48 :                         new->nfields = list_length($2);
     622          48 :                         new->fieldnames = palloc(new->nfields * sizeof(char *));
     623          48 :                         new->varnos = palloc(new->nfields * sizeof(int));
     624             : 
     625          48 :                         i = 0;
     626         144 :                         foreach (l, $2)
     627             :                         {
     628          96 :                             PLpgSQL_variable *arg = (PLpgSQL_variable *) lfirst(l);
     629             :                             Assert(!arg->isconst);
     630          96 :                             new->fieldnames[i] = arg->refname;
     631          96 :                             new->varnos[i] = arg->dno;
     632          96 :                             i++;
     633             :                         }
     634          48 :                         list_free($2);
     635             : 
     636          48 :                         plpgsql_adddatum((PLpgSQL_datum *) new);
     637          48 :                         $$ = (PLpgSQL_datum *) new;
     638             :                     }
     639             :                 ;
     640             : 
     641             : decl_cursor_arglist : decl_cursor_arg
     642             :                     {
     643          48 :                         $$ = list_make1($1);
     644             :                     }
     645             :                 | decl_cursor_arglist ',' decl_cursor_arg
     646             :                     {
     647          48 :                         $$ = lappend($1, $3);
     648             :                     }
     649             :                 ;
     650             : 
     651             : decl_cursor_arg : decl_varname decl_datatype
     652             :                     {
     653          96 :                         $$ = (PLpgSQL_datum *)
     654          96 :                             plpgsql_build_variable($1.name, $1.lineno,
     655             :                                                    $2, true);
     656             :                     }
     657             :                 ;
     658             : 
     659             : decl_is_for     :   K_IS |      /* Oracle */
     660             :                     K_FOR;      /* SQL standard */
     661             : 
     662             : decl_aliasitem  : T_WORD
     663             :                     {
     664             :                         PLpgSQL_nsitem *nsi;
     665             : 
     666          56 :                         nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false,
     667          56 :                                                 $1.ident, NULL, NULL,
     668             :                                                 NULL);
     669          56 :                         if (nsi == NULL)
     670           0 :                             ereport(ERROR,
     671             :                                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     672             :                                      errmsg("variable \"%s\" does not exist",
     673             :                                             $1.ident),
     674             :                                      parser_errposition(@1)));
     675          56 :                         $$ = nsi;
     676             :                     }
     677             :                 | unreserved_keyword
     678             :                     {
     679             :                         PLpgSQL_nsitem *nsi;
     680             : 
     681           0 :                         nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false,
     682             :                                                 $1, NULL, NULL,
     683             :                                                 NULL);
     684           0 :                         if (nsi == NULL)
     685           0 :                             ereport(ERROR,
     686             :                                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     687             :                                      errmsg("variable \"%s\" does not exist",
     688             :                                             $1),
     689             :                                      parser_errposition(@1)));
     690           0 :                         $$ = nsi;
     691             :                     }
     692             :                 | T_CWORD
     693             :                     {
     694             :                         PLpgSQL_nsitem *nsi;
     695             : 
     696           0 :                         if (list_length($1.idents) == 2)
     697           0 :                             nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false,
     698           0 :                                                     strVal(linitial($1.idents)),
     699           0 :                                                     strVal(lsecond($1.idents)),
     700             :                                                     NULL,
     701             :                                                     NULL);
     702           0 :                         else if (list_length($1.idents) == 3)
     703           0 :                             nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false,
     704           0 :                                                     strVal(linitial($1.idents)),
     705           0 :                                                     strVal(lsecond($1.idents)),
     706           0 :                                                     strVal(lthird($1.idents)),
     707             :                                                     NULL);
     708             :                         else
     709           0 :                             nsi = NULL;
     710           0 :                         if (nsi == NULL)
     711           0 :                             ereport(ERROR,
     712             :                                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     713             :                                      errmsg("variable \"%s\" does not exist",
     714             :                                             NameListToString($1.idents)),
     715             :                                      parser_errposition(@1)));
     716           0 :                         $$ = nsi;
     717             :                     }
     718             :                 ;
     719             : 
     720             : decl_varname    : T_WORD
     721             :                     {
     722        4230 :                         $$.name = $1.ident;
     723        4230 :                         $$.lineno = plpgsql_location_to_lineno(@1);
     724             :                         /*
     725             :                          * Check to make sure name isn't already declared
     726             :                          * in the current block.
     727             :                          */
     728        4230 :                         if (plpgsql_ns_lookup(plpgsql_ns_top(), true,
     729        4230 :                                               $1.ident, NULL, NULL,
     730             :                                               NULL) != NULL)
     731           0 :                             yyerror("duplicate declaration");
     732             : 
     733        4230 :                         if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR ||
     734        4182 :                             plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR)
     735             :                         {
     736             :                             PLpgSQL_nsitem *nsi;
     737          48 :                             nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false,
     738          48 :                                                     $1.ident, NULL, NULL, NULL);
     739          48 :                             if (nsi != NULL)
     740          36 :                                 ereport(plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR ? ERROR : WARNING,
     741             :                                         (errcode(ERRCODE_DUPLICATE_ALIAS),
     742             :                                          errmsg("variable \"%s\" shadows a previously defined variable",
     743             :                                                 $1.ident),
     744             :                                          parser_errposition(@1)));
     745             :                         }
     746             : 
     747             :                     }
     748             :                 | unreserved_keyword
     749             :                     {
     750          16 :                         $$.name = pstrdup($1);
     751          16 :                         $$.lineno = plpgsql_location_to_lineno(@1);
     752             :                         /*
     753             :                          * Check to make sure name isn't already declared
     754             :                          * in the current block.
     755             :                          */
     756          16 :                         if (plpgsql_ns_lookup(plpgsql_ns_top(), true,
     757             :                                               $1, NULL, NULL,
     758             :                                               NULL) != NULL)
     759           0 :                             yyerror("duplicate declaration");
     760             : 
     761          16 :                         if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR ||
     762          16 :                             plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR)
     763             :                         {
     764             :                             PLpgSQL_nsitem *nsi;
     765           0 :                             nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false,
     766             :                                                     $1, NULL, NULL, NULL);
     767           0 :                             if (nsi != NULL)
     768           0 :                                 ereport(plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR ? ERROR : WARNING,
     769             :                                         (errcode(ERRCODE_DUPLICATE_ALIAS),
     770             :                                          errmsg("variable \"%s\" shadows a previously defined variable",
     771             :                                                 $1),
     772             :                                          parser_errposition(@1)));
     773             :                         }
     774             : 
     775             :                     }
     776             :                 ;
     777             : 
     778             : decl_const      :
     779        4002 :                     { $$ = false; }
     780             :                 | K_CONSTANT
     781          14 :                     { $$ = true; }
     782             :                 ;
     783             : 
     784             : decl_datatype   :
     785             :                     {
     786             :                         /*
     787             :                          * If there's a lookahead token, read_datatype
     788             :                          * should consume it.
     789             :                          */
     790        4112 :                         $$ = read_datatype(yychar);
     791        4110 :                         yyclearin;
     792             :                     }
     793             :                 ;
     794             : 
     795             : decl_collate    :
     796        4014 :                     { $$ = InvalidOid; }
     797             :                 | K_COLLATE T_WORD
     798             :                     {
     799           0 :                         $$ = get_collation_oid(list_make1(makeString($2.ident)),
     800             :                                                false);
     801             :                     }
     802             :                 | K_COLLATE unreserved_keyword
     803             :                     {
     804           0 :                         $$ = get_collation_oid(list_make1(makeString(pstrdup($2))),
     805             :                                                false);
     806             :                     }
     807             :                 | K_COLLATE T_CWORD
     808             :                     {
     809           0 :                         $$ = get_collation_oid($2.idents, false);
     810             :                     }
     811             :                 ;
     812             : 
     813             : decl_notnull    :
     814        3992 :                     { $$ = false; }
     815             :                 | K_NOT K_NULL
     816          22 :                     { $$ = true; }
     817             :                 ;
     818             : 
     819             : decl_defval     : ';'
     820        3576 :                     { $$ = NULL; }
     821             :                 | decl_defkey
     822             :                     {
     823         438 :                         $$ = read_sql_expression(';', ";");
     824             :                     }
     825             :                 ;
     826             : 
     827             : decl_defkey     : assign_operator
     828             :                 | K_DEFAULT
     829             :                 ;
     830             : 
     831             : /*
     832             :  * Ada-based PL/SQL uses := for assignment and variable defaults, while
     833             :  * the SQL standard uses equals for these cases and for GET
     834             :  * DIAGNOSTICS, so we support both.  FOR and OPEN only support :=.
     835             :  */
     836             : assign_operator : '='
     837             :                 | COLON_EQUALS
     838             :                 ;
     839             : 
     840             : proc_sect       :
     841       10986 :                     { $$ = NIL; }
     842             :                 | proc_sect proc_stmt
     843             :                     {
     844             :                         /* don't bother linking null statements into list */
     845       23074 :                         if ($2 == NULL)
     846          20 :                             $$ = $1;
     847             :                         else
     848       23054 :                             $$ = lappend($1, $2);
     849             :                     }
     850             :                 ;
     851             : 
     852             : proc_stmt       : pl_block ';'
     853         154 :                         { $$ = $1; }
     854             :                 | stmt_assign
     855        6248 :                         { $$ = $1; }
     856             :                 | stmt_if
     857        3514 :                         { $$ = $1; }
     858             :                 | stmt_case
     859          12 :                         { $$ = $1; }
     860             :                 | stmt_loop
     861          40 :                         { $$ = $1; }
     862             :                 | stmt_while
     863          62 :                         { $$ = $1; }
     864             :                 | stmt_for
     865         686 :                         { $$ = $1; }
     866             :                 | stmt_foreach_a
     867          40 :                         { $$ = $1; }
     868             :                 | stmt_exit
     869         114 :                         { $$ = $1; }
     870             :                 | stmt_return
     871        5122 :                         { $$ = $1; }
     872             :                 | stmt_raise
     873        3944 :                         { $$ = $1; }
     874             :                 | stmt_assert
     875          34 :                         { $$ = $1; }
     876             :                 | stmt_execsql
     877        1668 :                         { $$ = $1; }
     878             :                 | stmt_dynexecute
     879         618 :                         { $$ = $1; }
     880             :                 | stmt_perform
     881         354 :                         { $$ = $1; }
     882             :                 | stmt_call
     883          82 :                         { $$ = $1; }
     884             :                 | stmt_getdiag
     885          52 :                         { $$ = $1; }
     886             :                 | stmt_open
     887          68 :                         { $$ = $1; }
     888             :                 | stmt_fetch
     889          80 :                         { $$ = $1; }
     890             :                 | stmt_move
     891          12 :                         { $$ = $1; }
     892             :                 | stmt_close
     893          44 :                         { $$ = $1; }
     894             :                 | stmt_null
     895          20 :                         { $$ = $1; }
     896             :                 | stmt_commit
     897          74 :                         { $$ = $1; }
     898             :                 | stmt_rollback
     899          32 :                         { $$ = $1; }
     900             :                 ;
     901             : 
     902             : stmt_perform    : K_PERFORM
     903         354 :                     {
     904             :                         PLpgSQL_stmt_perform *new;
     905             :                         int     startloc;
     906             : 
     907         354 :                         new = palloc0(sizeof(PLpgSQL_stmt_perform));
     908         354 :                         new->cmd_type = PLPGSQL_STMT_PERFORM;
     909         354 :                         new->lineno   = plpgsql_location_to_lineno(@1);
     910         354 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
     911         354 :                         plpgsql_push_back_token(K_PERFORM);
     912             : 
     913             :                         /*
     914             :                          * Since PERFORM isn't legal SQL, we have to cheat to
     915             :                          * the extent of substituting "SELECT" for "PERFORM"
     916             :                          * in the parsed text.  It does not seem worth
     917             :                          * inventing a separate parse mode for this one case.
     918             :                          * We can't do syntax-checking until after we make the
     919             :                          * substitution.
     920             :                          */
     921         354 :                         new->expr = read_sql_construct(';', 0, 0, ";",
     922             :                                                        RAW_PARSE_DEFAULT,
     923             :                                                        false, false, true,
     924             :                                                        &startloc, NULL);
     925             :                         /* overwrite "perform" ... */
     926         354 :                         memcpy(new->expr->query, " SELECT", 7);
     927             :                         /* left-justify to get rid of the leading space */
     928         354 :                         memmove(new->expr->query, new->expr->query + 1,
     929         354 :                                 strlen(new->expr->query));
     930             :                         /* offset syntax error position to account for that */
     931         354 :                         check_sql_expr(new->expr->query, new->expr->parseMode,
     932             :                                        startloc + 1);
     933             : 
     934         354 :                         $$ = (PLpgSQL_stmt *)new;
     935             :                     }
     936             :                 ;
     937             : 
     938             : stmt_call       : K_CALL
     939             :                     {
     940             :                         PLpgSQL_stmt_call *new;
     941             : 
     942          80 :                         new = palloc0(sizeof(PLpgSQL_stmt_call));
     943          80 :                         new->cmd_type = PLPGSQL_STMT_CALL;
     944          80 :                         new->lineno = plpgsql_location_to_lineno(@1);
     945          80 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
     946          80 :                         plpgsql_push_back_token(K_CALL);
     947          80 :                         new->expr = read_sql_stmt();
     948          80 :                         new->is_call = true;
     949             : 
     950             :                         /* Remember we may need a procedure resource owner */
     951          80 :                         plpgsql_curr_compile->requires_procedure_resowner = true;
     952             : 
     953          80 :                         $$ = (PLpgSQL_stmt *)new;
     954             : 
     955             :                     }
     956             :                 | K_DO
     957             :                     {
     958             :                         /* use the same structures as for CALL, for simplicity */
     959             :                         PLpgSQL_stmt_call *new;
     960             : 
     961           2 :                         new = palloc0(sizeof(PLpgSQL_stmt_call));
     962           2 :                         new->cmd_type = PLPGSQL_STMT_CALL;
     963           2 :                         new->lineno = plpgsql_location_to_lineno(@1);
     964           2 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
     965           2 :                         plpgsql_push_back_token(K_DO);
     966           2 :                         new->expr = read_sql_stmt();
     967           2 :                         new->is_call = false;
     968             : 
     969             :                         /* Remember we may need a procedure resource owner */
     970           2 :                         plpgsql_curr_compile->requires_procedure_resowner = true;
     971             : 
     972           2 :                         $$ = (PLpgSQL_stmt *)new;
     973             : 
     974             :                     }
     975             :                 ;
     976             : 
     977             : stmt_assign     : T_DATUM
     978             :                     {
     979             :                         PLpgSQL_stmt_assign *new;
     980             :                         RawParseMode pmode;
     981             : 
     982             :                         /* see how many names identify the datum */
     983        6254 :                         switch ($1.ident ? 1 : list_length($1.idents))
     984             :                         {
     985        5810 :                             case 1:
     986        5810 :                                 pmode = RAW_PARSE_PLPGSQL_ASSIGN1;
     987        5810 :                                 break;
     988         430 :                             case 2:
     989         430 :                                 pmode = RAW_PARSE_PLPGSQL_ASSIGN2;
     990         430 :                                 break;
     991          14 :                             case 3:
     992          14 :                                 pmode = RAW_PARSE_PLPGSQL_ASSIGN3;
     993          14 :                                 break;
     994           0 :                             default:
     995           0 :                                 elog(ERROR, "unexpected number of names");
     996             :                                 pmode = 0; /* keep compiler quiet */
     997             :                         }
     998             : 
     999        6254 :                         check_assignable($1.datum, @1);
    1000        6248 :                         new = palloc0(sizeof(PLpgSQL_stmt_assign));
    1001        6248 :                         new->cmd_type = PLPGSQL_STMT_ASSIGN;
    1002        6248 :                         new->lineno   = plpgsql_location_to_lineno(@1);
    1003        6248 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    1004        6248 :                         new->varno = $1.datum->dno;
    1005             :                         /* Push back the head name to include it in the stmt */
    1006        6248 :                         plpgsql_push_back_token(T_DATUM);
    1007        6248 :                         new->expr = read_sql_construct(';', 0, 0, ";",
    1008             :                                                        pmode,
    1009             :                                                        false, true, true,
    1010             :                                                        NULL, NULL);
    1011             : 
    1012        6248 :                         $$ = (PLpgSQL_stmt *)new;
    1013             :                     }
    1014             :                 ;
    1015             : 
    1016             : stmt_getdiag    : K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';'
    1017             :                     {
    1018             :                         PLpgSQL_stmt_getdiag     *new;
    1019             :                         ListCell        *lc;
    1020             : 
    1021          52 :                         new = palloc0(sizeof(PLpgSQL_stmt_getdiag));
    1022          52 :                         new->cmd_type = PLPGSQL_STMT_GETDIAG;
    1023          52 :                         new->lineno   = plpgsql_location_to_lineno(@1);
    1024          52 :                         new->stmtid    = ++plpgsql_curr_compile->nstatements;
    1025          52 :                         new->is_stacked = $2;
    1026          52 :                         new->diag_items = $4;
    1027             : 
    1028             :                         /*
    1029             :                          * Check information items are valid for area option.
    1030             :                          */
    1031         160 :                         foreach(lc, new->diag_items)
    1032             :                         {
    1033         108 :                             PLpgSQL_diag_item *ditem = (PLpgSQL_diag_item *) lfirst(lc);
    1034             : 
    1035         108 :                             switch (ditem->kind)
    1036             :                             {
    1037             :                                 /* these fields are disallowed in stacked case */
    1038          16 :                                 case PLPGSQL_GETDIAG_ROW_COUNT:
    1039          16 :                                     if (new->is_stacked)
    1040           0 :                                         ereport(ERROR,
    1041             :                                                 (errcode(ERRCODE_SYNTAX_ERROR),
    1042             :                                                  errmsg("diagnostics item %s is not allowed in GET STACKED DIAGNOSTICS",
    1043             :                                                         plpgsql_getdiag_kindname(ditem->kind)),
    1044             :                                                  parser_errposition(@1)));
    1045          16 :                                     break;
    1046             :                                 /* these fields are disallowed in current case */
    1047          76 :                                 case PLPGSQL_GETDIAG_ERROR_CONTEXT:
    1048             :                                 case PLPGSQL_GETDIAG_ERROR_DETAIL:
    1049             :                                 case PLPGSQL_GETDIAG_ERROR_HINT:
    1050             :                                 case PLPGSQL_GETDIAG_RETURNED_SQLSTATE:
    1051             :                                 case PLPGSQL_GETDIAG_COLUMN_NAME:
    1052             :                                 case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
    1053             :                                 case PLPGSQL_GETDIAG_DATATYPE_NAME:
    1054             :                                 case PLPGSQL_GETDIAG_MESSAGE_TEXT:
    1055             :                                 case PLPGSQL_GETDIAG_TABLE_NAME:
    1056             :                                 case PLPGSQL_GETDIAG_SCHEMA_NAME:
    1057          76 :                                     if (!new->is_stacked)
    1058           0 :                                         ereport(ERROR,
    1059             :                                                 (errcode(ERRCODE_SYNTAX_ERROR),
    1060             :                                                  errmsg("diagnostics item %s is not allowed in GET CURRENT DIAGNOSTICS",
    1061             :                                                         plpgsql_getdiag_kindname(ditem->kind)),
    1062             :                                                  parser_errposition(@1)));
    1063          76 :                                     break;
    1064             :                                 /* these fields are allowed in either case */
    1065          16 :                                 case PLPGSQL_GETDIAG_CONTEXT:
    1066          16 :                                     break;
    1067           0 :                                 default:
    1068           0 :                                     elog(ERROR, "unrecognized diagnostic item kind: %d",
    1069             :                                          ditem->kind);
    1070             :                                     break;
    1071             :                             }
    1072             :                         }
    1073             : 
    1074          52 :                         $$ = (PLpgSQL_stmt *)new;
    1075             :                     }
    1076             :                 ;
    1077             : 
    1078             : getdiag_area_opt :
    1079             :                     {
    1080          36 :                         $$ = false;
    1081             :                     }
    1082             :                 | K_CURRENT
    1083             :                     {
    1084           0 :                         $$ = false;
    1085             :                     }
    1086             :                 | K_STACKED
    1087             :                     {
    1088          20 :                         $$ = true;
    1089             :                     }
    1090             :                 ;
    1091             : 
    1092             : getdiag_list : getdiag_list ',' getdiag_list_item
    1093             :                     {
    1094          56 :                         $$ = lappend($1, $3);
    1095             :                     }
    1096             :                 | getdiag_list_item
    1097             :                     {
    1098          52 :                         $$ = list_make1($1);
    1099             :                     }
    1100             :                 ;
    1101             : 
    1102             : getdiag_list_item : getdiag_target assign_operator getdiag_item
    1103             :                     {
    1104             :                         PLpgSQL_diag_item *new;
    1105             : 
    1106         108 :                         new = palloc(sizeof(PLpgSQL_diag_item));
    1107         108 :                         new->target = $1->dno;
    1108         108 :                         new->kind = $3;
    1109             : 
    1110         108 :                         $$ = new;
    1111             :                     }
    1112             :                 ;
    1113             : 
    1114             : getdiag_item :
    1115             :                     {
    1116         108 :                         int tok = yylex();
    1117             : 
    1118         108 :                         if (tok_is_keyword(tok, &yylval,
    1119             :                                            K_ROW_COUNT, "row_count"))
    1120          16 :                             $$ = PLPGSQL_GETDIAG_ROW_COUNT;
    1121          92 :                         else if (tok_is_keyword(tok, &yylval,
    1122             :                                                 K_PG_CONTEXT, "pg_context"))
    1123          16 :                             $$ = PLPGSQL_GETDIAG_CONTEXT;
    1124          76 :                         else if (tok_is_keyword(tok, &yylval,
    1125             :                                                 K_PG_EXCEPTION_DETAIL, "pg_exception_detail"))
    1126          12 :                             $$ = PLPGSQL_GETDIAG_ERROR_DETAIL;
    1127          64 :                         else if (tok_is_keyword(tok, &yylval,
    1128             :                                                 K_PG_EXCEPTION_HINT, "pg_exception_hint"))
    1129          10 :                             $$ = PLPGSQL_GETDIAG_ERROR_HINT;
    1130          54 :                         else if (tok_is_keyword(tok, &yylval,
    1131             :                                                 K_PG_EXCEPTION_CONTEXT, "pg_exception_context"))
    1132           4 :                             $$ = PLPGSQL_GETDIAG_ERROR_CONTEXT;
    1133          50 :                         else if (tok_is_keyword(tok, &yylval,
    1134             :                                                 K_COLUMN_NAME, "column_name"))
    1135           6 :                             $$ = PLPGSQL_GETDIAG_COLUMN_NAME;
    1136          44 :                         else if (tok_is_keyword(tok, &yylval,
    1137             :                                                 K_CONSTRAINT_NAME, "constraint_name"))
    1138           6 :                             $$ = PLPGSQL_GETDIAG_CONSTRAINT_NAME;
    1139          38 :                         else if (tok_is_keyword(tok, &yylval,
    1140             :                                                 K_PG_DATATYPE_NAME, "pg_datatype_name"))
    1141           6 :                             $$ = PLPGSQL_GETDIAG_DATATYPE_NAME;
    1142          32 :                         else if (tok_is_keyword(tok, &yylval,
    1143             :                                                 K_MESSAGE_TEXT, "message_text"))
    1144          14 :                             $$ = PLPGSQL_GETDIAG_MESSAGE_TEXT;
    1145          18 :                         else if (tok_is_keyword(tok, &yylval,
    1146             :                                                 K_TABLE_NAME, "table_name"))
    1147           6 :                             $$ = PLPGSQL_GETDIAG_TABLE_NAME;
    1148          12 :                         else if (tok_is_keyword(tok, &yylval,
    1149             :                                                 K_SCHEMA_NAME, "schema_name"))
    1150           6 :                             $$ = PLPGSQL_GETDIAG_SCHEMA_NAME;
    1151           6 :                         else if (tok_is_keyword(tok, &yylval,
    1152             :                                                 K_RETURNED_SQLSTATE, "returned_sqlstate"))
    1153           6 :                             $$ = PLPGSQL_GETDIAG_RETURNED_SQLSTATE;
    1154             :                         else
    1155           0 :                             yyerror("unrecognized GET DIAGNOSTICS item");
    1156             :                     }
    1157             :                 ;
    1158             : 
    1159             : getdiag_target  : T_DATUM
    1160             :                     {
    1161             :                         /*
    1162             :                          * In principle we should support a getdiag_target
    1163             :                          * that is an array element, but for now we don't, so
    1164             :                          * just throw an error if next token is '['.
    1165             :                          */
    1166         112 :                         if ($1.datum->dtype == PLPGSQL_DTYPE_ROW ||
    1167         220 :                             $1.datum->dtype == PLPGSQL_DTYPE_REC ||
    1168         108 :                             plpgsql_peek() == '[')
    1169           4 :                             ereport(ERROR,
    1170             :                                     (errcode(ERRCODE_SYNTAX_ERROR),
    1171             :                                      errmsg("\"%s\" is not a scalar variable",
    1172             :                                             NameOfDatum(&($1))),
    1173             :                                      parser_errposition(@1)));
    1174         108 :                         check_assignable($1.datum, @1);
    1175         108 :                         $$ = $1.datum;
    1176             :                     }
    1177             :                 | T_WORD
    1178             :                     {
    1179             :                         /* just to give a better message than "syntax error" */
    1180           0 :                         word_is_not_variable(&($1), @1);
    1181             :                     }
    1182             :                 | T_CWORD
    1183             :                     {
    1184             :                         /* just to give a better message than "syntax error" */
    1185           0 :                         cword_is_not_variable(&($1), @1);
    1186             :                     }
    1187             :                 ;
    1188             : 
    1189             : stmt_if         : K_IF expr_until_then proc_sect stmt_elsifs stmt_else K_END K_IF ';'
    1190             :                     {
    1191             :                         PLpgSQL_stmt_if *new;
    1192             : 
    1193        3514 :                         new = palloc0(sizeof(PLpgSQL_stmt_if));
    1194        3514 :                         new->cmd_type    = PLPGSQL_STMT_IF;
    1195        3514 :                         new->lineno      = plpgsql_location_to_lineno(@1);
    1196        3514 :                         new->stmtid      = ++plpgsql_curr_compile->nstatements;
    1197        3514 :                         new->cond        = $2;
    1198        3514 :                         new->then_body   = $3;
    1199        3514 :                         new->elsif_list = $4;
    1200        3514 :                         new->else_body  = $5;
    1201             : 
    1202        3514 :                         $$ = (PLpgSQL_stmt *)new;
    1203             :                     }
    1204             :                 ;
    1205             : 
    1206             : stmt_elsifs     :
    1207             :                     {
    1208        3514 :                         $$ = NIL;
    1209             :                     }
    1210             :                 | stmt_elsifs K_ELSIF expr_until_then proc_sect
    1211             :                     {
    1212             :                         PLpgSQL_if_elsif *new;
    1213             : 
    1214         794 :                         new = palloc0(sizeof(PLpgSQL_if_elsif));
    1215         794 :                         new->lineno = plpgsql_location_to_lineno(@2);
    1216         794 :                         new->cond   = $3;
    1217         794 :                         new->stmts  = $4;
    1218             : 
    1219         794 :                         $$ = lappend($1, new);
    1220             :                     }
    1221             :                 ;
    1222             : 
    1223             : stmt_else       :
    1224             :                     {
    1225        3142 :                         $$ = NIL;
    1226             :                     }
    1227             :                 | K_ELSE proc_sect
    1228             :                     {
    1229         372 :                         $$ = $2;
    1230             :                     }
    1231             :                 ;
    1232             : 
    1233             : stmt_case       : K_CASE opt_expr_until_when case_when_list opt_case_else K_END K_CASE ';'
    1234             :                     {
    1235          12 :                         $$ = make_case(@1, $2, $3, $4);
    1236             :                     }
    1237             :                 ;
    1238             : 
    1239             : opt_expr_until_when :
    1240             :                     {
    1241          12 :                         PLpgSQL_expr *expr = NULL;
    1242          12 :                         int tok = yylex();
    1243             : 
    1244          12 :                         if (tok != K_WHEN)
    1245             :                         {
    1246          10 :                             plpgsql_push_back_token(tok);
    1247          10 :                             expr = read_sql_expression(K_WHEN, "WHEN");
    1248             :                         }
    1249          12 :                         plpgsql_push_back_token(K_WHEN);
    1250          12 :                         $$ = expr;
    1251             :                     }
    1252             :                 ;
    1253             : 
    1254             : case_when_list  : case_when_list case_when
    1255             :                     {
    1256          18 :                         $$ = lappend($1, $2);
    1257             :                     }
    1258             :                 | case_when
    1259             :                     {
    1260          12 :                         $$ = list_make1($1);
    1261             :                     }
    1262             :                 ;
    1263             : 
    1264             : case_when       : K_WHEN expr_until_then proc_sect
    1265             :                     {
    1266          30 :                         PLpgSQL_case_when *new = palloc(sizeof(PLpgSQL_case_when));
    1267             : 
    1268          30 :                         new->lineno  = plpgsql_location_to_lineno(@1);
    1269          30 :                         new->expr    = $2;
    1270          30 :                         new->stmts   = $3;
    1271          30 :                         $$ = new;
    1272             :                     }
    1273             :                 ;
    1274             : 
    1275             : opt_case_else   :
    1276             :                     {
    1277          10 :                         $$ = NIL;
    1278             :                     }
    1279             :                 | K_ELSE proc_sect
    1280             :                     {
    1281             :                         /*
    1282             :                          * proc_sect could return an empty list, but we
    1283             :                          * must distinguish that from not having ELSE at all.
    1284             :                          * Simplest fix is to return a list with one NULL
    1285             :                          * pointer, which make_case() must take care of.
    1286             :                          */
    1287           2 :                         if ($2 != NIL)
    1288           2 :                             $$ = $2;
    1289             :                         else
    1290           0 :                             $$ = list_make1(NULL);
    1291             :                     }
    1292             :                 ;
    1293             : 
    1294             : stmt_loop       : opt_loop_label K_LOOP loop_body
    1295             :                     {
    1296             :                         PLpgSQL_stmt_loop *new;
    1297             : 
    1298          40 :                         new = palloc0(sizeof(PLpgSQL_stmt_loop));
    1299          40 :                         new->cmd_type = PLPGSQL_STMT_LOOP;
    1300          40 :                         new->lineno   = plpgsql_location_to_lineno(@2);
    1301          40 :                         new->stmtid   = ++plpgsql_curr_compile->nstatements;
    1302          40 :                         new->label     = $1;
    1303          40 :                         new->body      = $3.stmts;
    1304             : 
    1305          40 :                         check_labels($1, $3.end_label, $3.end_label_location);
    1306          40 :                         plpgsql_ns_pop();
    1307             : 
    1308          40 :                         $$ = (PLpgSQL_stmt *)new;
    1309             :                     }
    1310             :                 ;
    1311             : 
    1312             : stmt_while      : opt_loop_label K_WHILE expr_until_loop loop_body
    1313             :                     {
    1314             :                         PLpgSQL_stmt_while *new;
    1315             : 
    1316          62 :                         new = palloc0(sizeof(PLpgSQL_stmt_while));
    1317          62 :                         new->cmd_type = PLPGSQL_STMT_WHILE;
    1318          62 :                         new->lineno   = plpgsql_location_to_lineno(@2);
    1319          62 :                         new->stmtid    = ++plpgsql_curr_compile->nstatements;
    1320          62 :                         new->label     = $1;
    1321          62 :                         new->cond      = $3;
    1322          62 :                         new->body      = $4.stmts;
    1323             : 
    1324          62 :                         check_labels($1, $4.end_label, $4.end_label_location);
    1325          62 :                         plpgsql_ns_pop();
    1326             : 
    1327          62 :                         $$ = (PLpgSQL_stmt *)new;
    1328             :                     }
    1329             :                 ;
    1330             : 
    1331             : stmt_for        : opt_loop_label K_FOR for_control loop_body
    1332             :                     {
    1333             :                         /* This runs after we've scanned the loop body */
    1334         692 :                         if ($3->cmd_type == PLPGSQL_STMT_FORI)
    1335             :                         {
    1336             :                             PLpgSQL_stmt_fori       *new;
    1337             : 
    1338         236 :                             new = (PLpgSQL_stmt_fori *) $3;
    1339         236 :                             new->lineno   = plpgsql_location_to_lineno(@2);
    1340         236 :                             new->label     = $1;
    1341         236 :                             new->body      = $4.stmts;
    1342         236 :                             $$ = (PLpgSQL_stmt *) new;
    1343             :                         }
    1344             :                         else
    1345             :                         {
    1346             :                             PLpgSQL_stmt_forq       *new;
    1347             : 
    1348             :                             Assert($3->cmd_type == PLPGSQL_STMT_FORS ||
    1349             :                                    $3->cmd_type == PLPGSQL_STMT_FORC ||
    1350             :                                    $3->cmd_type == PLPGSQL_STMT_DYNFORS);
    1351             :                             /* forq is the common supertype of all three */
    1352         456 :                             new = (PLpgSQL_stmt_forq *) $3;
    1353         456 :                             new->lineno   = plpgsql_location_to_lineno(@2);
    1354         456 :                             new->label     = $1;
    1355         456 :                             new->body      = $4.stmts;
    1356         456 :                             $$ = (PLpgSQL_stmt *) new;
    1357             :                         }
    1358             : 
    1359         692 :                         check_labels($1, $4.end_label, $4.end_label_location);
    1360             :                         /* close namespace started in opt_loop_label */
    1361         686 :                         plpgsql_ns_pop();
    1362             :                     }
    1363             :                 ;
    1364             : 
    1365             : for_control     : for_variable K_IN
    1366         692 :                     {
    1367         700 :                         int         tok = yylex();
    1368         700 :                         int         tokloc = yylloc;
    1369             : 
    1370         700 :                         if (tok == K_EXECUTE)
    1371             :                         {
    1372             :                             /* EXECUTE means it's a dynamic FOR loop */
    1373             :                             PLpgSQL_stmt_dynfors    *new;
    1374             :                             PLpgSQL_expr            *expr;
    1375             :                             int                     term;
    1376             : 
    1377         138 :                             expr = read_sql_expression2(K_LOOP, K_USING,
    1378             :                                                         "LOOP or USING",
    1379             :                                                         &term);
    1380             : 
    1381         138 :                             new = palloc0(sizeof(PLpgSQL_stmt_dynfors));
    1382         138 :                             new->cmd_type = PLPGSQL_STMT_DYNFORS;
    1383         138 :                             new->stmtid    = ++plpgsql_curr_compile->nstatements;
    1384         138 :                             if ($1.row)
    1385             :                             {
    1386          34 :                                 new->var = (PLpgSQL_variable *) $1.row;
    1387          34 :                                 check_assignable($1.row, @1);
    1388             :                             }
    1389         104 :                             else if ($1.scalar)
    1390             :                             {
    1391             :                                 /* convert single scalar to list */
    1392         104 :                                 new->var = (PLpgSQL_variable *)
    1393         208 :                                     make_scalar_list1($1.name, $1.scalar,
    1394         104 :                                                       $1.lineno, @1);
    1395             :                                 /* make_scalar_list1 did check_assignable */
    1396             :                             }
    1397             :                             else
    1398             :                             {
    1399           0 :                                 ereport(ERROR,
    1400             :                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    1401             :                                          errmsg("loop variable of loop over rows must be a record variable or list of scalar variables"),
    1402             :                                          parser_errposition(@1)));
    1403             :                             }
    1404         138 :                             new->query = expr;
    1405             : 
    1406         138 :                             if (term == K_USING)
    1407             :                             {
    1408             :                                 do
    1409             :                                 {
    1410           8 :                                     expr = read_sql_expression2(',', K_LOOP,
    1411             :                                                                 ", or LOOP",
    1412             :                                                                 &term);
    1413           8 :                                     new->params = lappend(new->params, expr);
    1414           8 :                                 } while (term == ',');
    1415             :                             }
    1416             : 
    1417         138 :                             $$ = (PLpgSQL_stmt *) new;
    1418             :                         }
    1419         562 :                         else if (tok == T_DATUM &&
    1420          46 :                                  yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_VAR &&
    1421          46 :                                  ((PLpgSQL_var *) yylval.wdatum.datum)->datatype->typoid == REFCURSOROID)
    1422          26 :                         {
    1423             :                             /* It's FOR var IN cursor */
    1424             :                             PLpgSQL_stmt_forc   *new;
    1425          30 :                             PLpgSQL_var         *cursor = (PLpgSQL_var *) yylval.wdatum.datum;
    1426             : 
    1427          30 :                             new = (PLpgSQL_stmt_forc *) palloc0(sizeof(PLpgSQL_stmt_forc));
    1428          30 :                             new->cmd_type = PLPGSQL_STMT_FORC;
    1429          30 :                             new->stmtid = ++plpgsql_curr_compile->nstatements;
    1430          30 :                             new->curvar = cursor->dno;
    1431             : 
    1432             :                             /* Should have had a single variable name */
    1433          30 :                             if ($1.scalar && $1.row)
    1434           0 :                                 ereport(ERROR,
    1435             :                                         (errcode(ERRCODE_SYNTAX_ERROR),
    1436             :                                          errmsg("cursor FOR loop must have only one target variable"),
    1437             :                                          parser_errposition(@1)));
    1438             : 
    1439             :                             /* can't use an unbound cursor this way */
    1440          30 :                             if (cursor->cursor_explicit_expr == NULL)
    1441           4 :                                 ereport(ERROR,
    1442             :                                         (errcode(ERRCODE_SYNTAX_ERROR),
    1443             :                                          errmsg("cursor FOR loop must use a bound cursor variable"),
    1444             :                                          parser_errposition(tokloc)));
    1445             : 
    1446             :                             /* collect cursor's parameters if any */
    1447          26 :                             new->argquery = read_cursor_args(cursor,
    1448             :                                                              K_LOOP);
    1449             : 
    1450             :                             /* create loop's private RECORD variable */
    1451          26 :                             new->var = (PLpgSQL_variable *)
    1452          26 :                                 plpgsql_build_record($1.name,
    1453          26 :                                                      $1.lineno,
    1454             :                                                      NULL,
    1455             :                                                      RECORDOID,
    1456             :                                                      true);
    1457             : 
    1458          26 :                             $$ = (PLpgSQL_stmt *) new;
    1459             :                         }
    1460             :                         else
    1461             :                         {
    1462             :                             PLpgSQL_expr    *expr1;
    1463             :                             int             expr1loc;
    1464         532 :                             bool            reverse = false;
    1465             : 
    1466             :                             /*
    1467             :                              * We have to distinguish between two
    1468             :                              * alternatives: FOR var IN a .. b and FOR
    1469             :                              * var IN query. Unfortunately this is
    1470             :                              * tricky, since the query in the second
    1471             :                              * form needn't start with a SELECT
    1472             :                              * keyword.  We use the ugly hack of
    1473             :                              * looking for two periods after the first
    1474             :                              * token. We also check for the REVERSE
    1475             :                              * keyword, which means it must be an
    1476             :                              * integer loop.
    1477             :                              */
    1478         532 :                             if (tok_is_keyword(tok, &yylval,
    1479             :                                                K_REVERSE, "reverse"))
    1480           6 :                                 reverse = true;
    1481             :                             else
    1482         526 :                                 plpgsql_push_back_token(tok);
    1483             : 
    1484             :                             /*
    1485             :                              * Read tokens until we see either a ".."
    1486             :                              * or a LOOP.  The text we read may be either
    1487             :                              * an expression or a whole SQL statement, so
    1488             :                              * we need to invoke read_sql_construct directly,
    1489             :                              * and tell it not to check syntax yet.
    1490             :                              */
    1491         532 :                             expr1 = read_sql_construct(DOT_DOT,
    1492             :                                                        K_LOOP,
    1493             :                                                        0,
    1494             :                                                        "LOOP",
    1495             :                                                        RAW_PARSE_DEFAULT,
    1496             :                                                        true,
    1497             :                                                        false,
    1498             :                                                        true,
    1499             :                                                        &expr1loc,
    1500             :                                                        &tok);
    1501             : 
    1502         532 :                             if (tok == DOT_DOT)
    1503             :                             {
    1504             :                                 /* Saw "..", so it must be an integer loop */
    1505             :                                 PLpgSQL_expr        *expr2;
    1506             :                                 PLpgSQL_expr        *expr_by;
    1507             :                                 PLpgSQL_var         *fvar;
    1508             :                                 PLpgSQL_stmt_fori   *new;
    1509             : 
    1510             :                                 /*
    1511             :                                  * Relabel first expression as an expression;
    1512             :                                  * then we can check its syntax.
    1513             :                                  */
    1514         236 :                                 expr1->parseMode = RAW_PARSE_PLPGSQL_EXPR;
    1515         236 :                                 check_sql_expr(expr1->query, expr1->parseMode,
    1516             :                                                expr1loc);
    1517             : 
    1518             :                                 /* Read and check the second one */
    1519         236 :                                 expr2 = read_sql_expression2(K_LOOP, K_BY,
    1520             :                                                              "LOOP",
    1521             :                                                              &tok);
    1522             : 
    1523             :                                 /* Get the BY clause if any */
    1524         236 :                                 if (tok == K_BY)
    1525          18 :                                     expr_by = read_sql_expression(K_LOOP,
    1526             :                                                                   "LOOP");
    1527             :                                 else
    1528         218 :                                     expr_by = NULL;
    1529             : 
    1530             :                                 /* Should have had a single variable name */
    1531         236 :                                 if ($1.scalar && $1.row)
    1532           0 :                                     ereport(ERROR,
    1533             :                                             (errcode(ERRCODE_SYNTAX_ERROR),
    1534             :                                              errmsg("integer FOR loop must have only one target variable"),
    1535             :                                              parser_errposition(@1)));
    1536             : 
    1537             :                                 /* create loop's private variable */
    1538             :                                 fvar = (PLpgSQL_var *)
    1539         236 :                                     plpgsql_build_variable($1.name,
    1540         236 :                                                            $1.lineno,
    1541             :                                                            plpgsql_build_datatype(INT4OID,
    1542             :                                                                                   -1,
    1543             :                                                                                   InvalidOid,
    1544             :                                                                                   NULL),
    1545             :                                                            true);
    1546             : 
    1547         236 :                                 new = palloc0(sizeof(PLpgSQL_stmt_fori));
    1548         236 :                                 new->cmd_type = PLPGSQL_STMT_FORI;
    1549         236 :                                 new->stmtid    = ++plpgsql_curr_compile->nstatements;
    1550         236 :                                 new->var   = fvar;
    1551         236 :                                 new->reverse  = reverse;
    1552         236 :                                 new->lower     = expr1;
    1553         236 :                                 new->upper     = expr2;
    1554         236 :                                 new->step      = expr_by;
    1555             : 
    1556         236 :                                 $$ = (PLpgSQL_stmt *) new;
    1557             :                             }
    1558             :                             else
    1559             :                             {
    1560             :                                 /*
    1561             :                                  * No "..", so it must be a query loop.
    1562             :                                  */
    1563             :                                 PLpgSQL_stmt_fors   *new;
    1564             : 
    1565         296 :                                 if (reverse)
    1566           0 :                                     ereport(ERROR,
    1567             :                                             (errcode(ERRCODE_SYNTAX_ERROR),
    1568             :                                              errmsg("cannot specify REVERSE in query FOR loop"),
    1569             :                                              parser_errposition(tokloc)));
    1570             : 
    1571             :                                 /* Check syntax as a regular query */
    1572         296 :                                 check_sql_expr(expr1->query, expr1->parseMode,
    1573             :                                                expr1loc);
    1574             : 
    1575         292 :                                 new = palloc0(sizeof(PLpgSQL_stmt_fors));
    1576         292 :                                 new->cmd_type = PLPGSQL_STMT_FORS;
    1577         292 :                                 new->stmtid = ++plpgsql_curr_compile->nstatements;
    1578         292 :                                 if ($1.row)
    1579             :                                 {
    1580         206 :                                     new->var = (PLpgSQL_variable *) $1.row;
    1581         206 :                                     check_assignable($1.row, @1);
    1582             :                                 }
    1583          86 :                                 else if ($1.scalar)
    1584             :                                 {
    1585             :                                     /* convert single scalar to list */
    1586          86 :                                     new->var = (PLpgSQL_variable *)
    1587         172 :                                         make_scalar_list1($1.name, $1.scalar,
    1588          86 :                                                           $1.lineno, @1);
    1589             :                                     /* make_scalar_list1 did check_assignable */
    1590             :                                 }
    1591             :                                 else
    1592             :                                 {
    1593           0 :                                     ereport(ERROR,
    1594             :                                             (errcode(ERRCODE_SYNTAX_ERROR),
    1595             :                                              errmsg("loop variable of loop over rows must be a record variable or list of scalar variables"),
    1596             :                                              parser_errposition(@1)));
    1597             :                                 }
    1598             : 
    1599         292 :                                 new->query = expr1;
    1600         292 :                                 $$ = (PLpgSQL_stmt *) new;
    1601             :                             }
    1602             :                         }
    1603             :                     }
    1604             :                 ;
    1605             : 
    1606             : /*
    1607             :  * Processing the for_variable is tricky because we don't yet know if the
    1608             :  * FOR is an integer FOR loop or a loop over query results.  In the former
    1609             :  * case, the variable is just a name that we must instantiate as a loop
    1610             :  * local variable, regardless of any other definition it might have.
    1611             :  * Therefore, we always save the actual identifier into $$.name where it
    1612             :  * can be used for that case.  We also save the outer-variable definition,
    1613             :  * if any, because that's what we need for the loop-over-query case.  Note
    1614             :  * that we must NOT apply check_assignable() or any other semantic check
    1615             :  * until we know what's what.
    1616             :  *
    1617             :  * However, if we see a comma-separated list of names, we know that it
    1618             :  * can't be an integer FOR loop and so it's OK to check the variables
    1619             :  * immediately.  In particular, for T_WORD followed by comma, we should
    1620             :  * complain that the name is not known rather than say it's a syntax error.
    1621             :  * Note that the non-error result of this case sets *both* $$.scalar and
    1622             :  * $$.row; see the for_control production.
    1623             :  */
    1624             : for_variable    : T_DATUM
    1625             :                     {
    1626         494 :                         $$.name = NameOfDatum(&($1));
    1627         494 :                         $$.lineno = plpgsql_location_to_lineno(@1);
    1628         494 :                         if ($1.datum->dtype == PLPGSQL_DTYPE_ROW ||
    1629         494 :                             $1.datum->dtype == PLPGSQL_DTYPE_REC)
    1630             :                         {
    1631         248 :                             $$.scalar = NULL;
    1632         248 :                             $$.row = $1.datum;
    1633             :                         }
    1634             :                         else
    1635         230 :                         {
    1636             :                             int         tok;
    1637             : 
    1638         246 :                             $$.scalar = $1.datum;
    1639         246 :                             $$.row = NULL;
    1640             :                             /* check for comma-separated list */
    1641         246 :                             tok = yylex();
    1642         246 :                             plpgsql_push_back_token(tok);
    1643         246 :                             if (tok == ',')
    1644          12 :                                 $$.row = (PLpgSQL_datum *)
    1645          16 :                                     read_into_scalar_list($$.name,
    1646             :                                                           $$.scalar,
    1647             :                                                           @1);
    1648             :                         }
    1649             :                     }
    1650             :                 | T_WORD
    1651         252 :                     {
    1652             :                         int         tok;
    1653             : 
    1654         252 :                         $$.name = $1.ident;
    1655         252 :                         $$.lineno = plpgsql_location_to_lineno(@1);
    1656         252 :                         $$.scalar = NULL;
    1657         252 :                         $$.row = NULL;
    1658             :                         /* check for comma-separated list */
    1659         252 :                         tok = yylex();
    1660         252 :                         plpgsql_push_back_token(tok);
    1661         252 :                         if (tok == ',')
    1662           0 :                             word_is_not_variable(&($1), @1);
    1663             :                     }
    1664             :                 | T_CWORD
    1665             :                     {
    1666             :                         /* just to give a better message than "syntax error" */
    1667           0 :                         cword_is_not_variable(&($1), @1);
    1668             :                     }
    1669             :                 ;
    1670             : 
    1671             : stmt_foreach_a  : opt_loop_label K_FOREACH for_variable foreach_slice K_IN K_ARRAY expr_until_loop loop_body
    1672             :                     {
    1673             :                         PLpgSQL_stmt_foreach_a *new;
    1674             : 
    1675          40 :                         new = palloc0(sizeof(PLpgSQL_stmt_foreach_a));
    1676          40 :                         new->cmd_type = PLPGSQL_STMT_FOREACH_A;
    1677          40 :                         new->lineno = plpgsql_location_to_lineno(@2);
    1678          40 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    1679          40 :                         new->label = $1;
    1680          40 :                         new->slice = $4;
    1681          40 :                         new->expr = $7;
    1682          40 :                         new->body = $8.stmts;
    1683             : 
    1684          40 :                         if ($3.row)
    1685             :                         {
    1686          16 :                             new->varno = $3.row->dno;
    1687          16 :                             check_assignable($3.row, @3);
    1688             :                         }
    1689          24 :                         else if ($3.scalar)
    1690             :                         {
    1691          24 :                             new->varno = $3.scalar->dno;
    1692          24 :                             check_assignable($3.scalar, @3);
    1693             :                         }
    1694             :                         else
    1695             :                         {
    1696           0 :                             ereport(ERROR,
    1697             :                                     (errcode(ERRCODE_SYNTAX_ERROR),
    1698             :                                      errmsg("loop variable of FOREACH must be a known variable or list of variables"),
    1699             :                                              parser_errposition(@3)));
    1700             :                         }
    1701             : 
    1702          40 :                         check_labels($1, $8.end_label, $8.end_label_location);
    1703          40 :                         plpgsql_ns_pop();
    1704             : 
    1705          40 :                         $$ = (PLpgSQL_stmt *) new;
    1706             :                     }
    1707             :                 ;
    1708             : 
    1709             : foreach_slice   :
    1710             :                     {
    1711          20 :                         $$ = 0;
    1712             :                     }
    1713             :                 | K_SLICE ICONST
    1714             :                     {
    1715          20 :                         $$ = $2;
    1716             :                     }
    1717             :                 ;
    1718             : 
    1719             : stmt_exit       : exit_type opt_label opt_exitcond
    1720             :                     {
    1721             :                         PLpgSQL_stmt_exit *new;
    1722             : 
    1723         124 :                         new = palloc0(sizeof(PLpgSQL_stmt_exit));
    1724         124 :                         new->cmd_type = PLPGSQL_STMT_EXIT;
    1725         124 :                         new->stmtid    = ++plpgsql_curr_compile->nstatements;
    1726         124 :                         new->is_exit  = $1;
    1727         124 :                         new->lineno    = plpgsql_location_to_lineno(@1);
    1728         124 :                         new->label     = $2;
    1729         124 :                         new->cond      = $3;
    1730             : 
    1731         124 :                         if ($2)
    1732             :                         {
    1733             :                             /* We have a label, so verify it exists */
    1734             :                             PLpgSQL_nsitem *label;
    1735             : 
    1736          32 :                             label = plpgsql_ns_lookup_label(plpgsql_ns_top(), $2);
    1737          32 :                             if (label == NULL)
    1738           4 :                                 ereport(ERROR,
    1739             :                                         (errcode(ERRCODE_SYNTAX_ERROR),
    1740             :                                          errmsg("there is no label \"%s\" "
    1741             :                                                 "attached to any block or loop enclosing this statement",
    1742             :                                                 $2),
    1743             :                                          parser_errposition(@2)));
    1744             :                             /* CONTINUE only allows loop labels */
    1745          28 :                             if (label->itemno != PLPGSQL_LABEL_LOOP && !new->is_exit)
    1746           2 :                                 ereport(ERROR,
    1747             :                                         (errcode(ERRCODE_SYNTAX_ERROR),
    1748             :                                          errmsg("block label \"%s\" cannot be used in CONTINUE",
    1749             :                                                 $2),
    1750             :                                          parser_errposition(@2)));
    1751             :                         }
    1752             :                         else
    1753             :                         {
    1754             :                             /*
    1755             :                              * No label, so make sure there is some loop (an
    1756             :                              * unlabeled EXIT does not match a block, so this
    1757             :                              * is the same test for both EXIT and CONTINUE)
    1758             :                              */
    1759          92 :                             if (plpgsql_ns_find_nearest_loop(plpgsql_ns_top()) == NULL)
    1760           4 :                                 ereport(ERROR,
    1761             :                                         (errcode(ERRCODE_SYNTAX_ERROR),
    1762             :                                          new->is_exit ?
    1763             :                                          errmsg("EXIT cannot be used outside a loop, unless it has a label") :
    1764             :                                          errmsg("CONTINUE cannot be used outside a loop"),
    1765             :                                          parser_errposition(@1)));
    1766             :                         }
    1767             : 
    1768         114 :                         $$ = (PLpgSQL_stmt *)new;
    1769             :                     }
    1770             :                 ;
    1771             : 
    1772             : exit_type       : K_EXIT
    1773             :                     {
    1774          74 :                         $$ = true;
    1775             :                     }
    1776             :                 | K_CONTINUE
    1777             :                     {
    1778          50 :                         $$ = false;
    1779             :                     }
    1780             :                 ;
    1781             : 
    1782             : stmt_return     : K_RETURN
    1783             :                     {
    1784             :                         int tok;
    1785             : 
    1786        5140 :                         tok = yylex();
    1787        5140 :                         if (tok == 0)
    1788           0 :                             yyerror("unexpected end of function definition");
    1789             : 
    1790        5140 :                         if (tok_is_keyword(tok, &yylval,
    1791             :                                            K_NEXT, "next"))
    1792             :                         {
    1793         186 :                             $$ = make_return_next_stmt(@1);
    1794             :                         }
    1795        4954 :                         else if (tok_is_keyword(tok, &yylval,
    1796             :                                                 K_QUERY, "query"))
    1797             :                         {
    1798          96 :                             $$ = make_return_query_stmt(@1);
    1799             :                         }
    1800             :                         else
    1801             :                         {
    1802        4858 :                             plpgsql_push_back_token(tok);
    1803        4858 :                             $$ = make_return_stmt(@1);
    1804             :                         }
    1805             :                     }
    1806             :                 ;
    1807             : 
    1808             : stmt_raise      : K_RAISE
    1809        3944 :                     {
    1810             :                         PLpgSQL_stmt_raise      *new;
    1811             :                         int tok;
    1812             : 
    1813        3952 :                         new = palloc(sizeof(PLpgSQL_stmt_raise));
    1814             : 
    1815        3952 :                         new->cmd_type    = PLPGSQL_STMT_RAISE;
    1816        3952 :                         new->lineno      = plpgsql_location_to_lineno(@1);
    1817        3952 :                         new->stmtid      = ++plpgsql_curr_compile->nstatements;
    1818        3952 :                         new->elog_level = ERROR; /* default */
    1819        3952 :                         new->condname    = NULL;
    1820        3952 :                         new->message = NULL;
    1821        3952 :                         new->params      = NIL;
    1822        3952 :                         new->options = NIL;
    1823             : 
    1824        3952 :                         tok = yylex();
    1825        3952 :                         if (tok == 0)
    1826           0 :                             yyerror("unexpected end of function definition");
    1827             : 
    1828             :                         /*
    1829             :                          * We could have just RAISE, meaning to re-throw
    1830             :                          * the current error.
    1831             :                          */
    1832        3952 :                         if (tok != ';')
    1833             :                         {
    1834             :                             /*
    1835             :                              * First is an optional elog severity level.
    1836             :                              */
    1837        3920 :                             if (tok_is_keyword(tok, &yylval,
    1838             :                                                K_EXCEPTION, "exception"))
    1839             :                             {
    1840         378 :                                 new->elog_level = ERROR;
    1841         378 :                                 tok = yylex();
    1842             :                             }
    1843        3542 :                             else if (tok_is_keyword(tok, &yylval,
    1844             :                                                     K_WARNING, "warning"))
    1845             :                             {
    1846         128 :                                 new->elog_level = WARNING;
    1847         128 :                                 tok = yylex();
    1848             :                             }
    1849        3414 :                             else if (tok_is_keyword(tok, &yylval,
    1850             :                                                     K_NOTICE, "notice"))
    1851             :                             {
    1852        3130 :                                 new->elog_level = NOTICE;
    1853        3130 :                                 tok = yylex();
    1854             :                             }
    1855         284 :                             else if (tok_is_keyword(tok, &yylval,
    1856             :                                                     K_INFO, "info"))
    1857             :                             {
    1858         112 :                                 new->elog_level = INFO;
    1859         112 :                                 tok = yylex();
    1860             :                             }
    1861         172 :                             else if (tok_is_keyword(tok, &yylval,
    1862             :                                                     K_LOG, "log"))
    1863             :                             {
    1864          22 :                                 new->elog_level = LOG;
    1865          22 :                                 tok = yylex();
    1866             :                             }
    1867         150 :                             else if (tok_is_keyword(tok, &yylval,
    1868             :                                                     K_DEBUG, "debug"))
    1869             :                             {
    1870           0 :                                 new->elog_level = DEBUG1;
    1871           0 :                                 tok = yylex();
    1872             :                             }
    1873        3920 :                             if (tok == 0)
    1874           0 :                                 yyerror("unexpected end of function definition");
    1875             : 
    1876             :                             /*
    1877             :                              * Next we can have a condition name, or
    1878             :                              * equivalently SQLSTATE 'xxxxx', or a string
    1879             :                              * literal that is the old-style message format,
    1880             :                              * or USING to start the option list immediately.
    1881             :                              */
    1882        3920 :                             if (tok == SCONST)
    1883             :                             {
    1884             :                                 /* old style message and parameters */
    1885        3784 :                                 new->message = yylval.str;
    1886             :                                 /*
    1887             :                                  * We expect either a semi-colon, which
    1888             :                                  * indicates no parameters, or a comma that
    1889             :                                  * begins the list of parameter expressions,
    1890             :                                  * or USING to begin the options list.
    1891             :                                  */
    1892        3784 :                                 tok = yylex();
    1893        3784 :                                 if (tok != ',' && tok != ';' && tok != K_USING)
    1894           0 :                                     yyerror("syntax error");
    1895             : 
    1896       13556 :                                 while (tok == ',')
    1897             :                                 {
    1898             :                                     PLpgSQL_expr *expr;
    1899             : 
    1900        9772 :                                     expr = read_sql_construct(',', ';', K_USING,
    1901             :                                                               ", or ; or USING",
    1902             :                                                               RAW_PARSE_PLPGSQL_EXPR,
    1903             :                                                               true, true, true,
    1904             :                                                               NULL, &tok);
    1905        9772 :                                     new->params = lappend(new->params, expr);
    1906             :                                 }
    1907             :                             }
    1908         136 :                             else if (tok != K_USING)
    1909             :                             {
    1910             :                                 /* must be condition name or SQLSTATE */
    1911         124 :                                 if (tok_is_keyword(tok, &yylval,
    1912             :                                                    K_SQLSTATE, "sqlstate"))
    1913             :                                 {
    1914             :                                     /* next token should be a string literal */
    1915             :                                     char   *sqlstatestr;
    1916             : 
    1917          96 :                                     if (yylex() != SCONST)
    1918           0 :                                         yyerror("syntax error");
    1919          96 :                                     sqlstatestr = yylval.str;
    1920             : 
    1921          96 :                                     if (strlen(sqlstatestr) != 5)
    1922           0 :                                         yyerror("invalid SQLSTATE code");
    1923          96 :                                     if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5)
    1924           0 :                                         yyerror("invalid SQLSTATE code");
    1925          96 :                                     new->condname = sqlstatestr;
    1926             :                                 }
    1927             :                                 else
    1928             :                                 {
    1929          28 :                                     if (tok == T_WORD)
    1930          28 :                                         new->condname = yylval.word.ident;
    1931           0 :                                     else if (plpgsql_token_is_unreserved_keyword(tok))
    1932           0 :                                         new->condname = pstrdup(yylval.keyword);
    1933             :                                     else
    1934           0 :                                         yyerror("syntax error");
    1935          28 :                                     plpgsql_recognize_err_condition(new->condname,
    1936             :                                                                     false);
    1937             :                                 }
    1938         124 :                                 tok = yylex();
    1939         124 :                                 if (tok != ';' && tok != K_USING)
    1940           0 :                                     yyerror("syntax error");
    1941             :                             }
    1942             : 
    1943        3920 :                             if (tok == K_USING)
    1944         148 :                                 new->options = read_raise_options();
    1945             :                         }
    1946             : 
    1947        3952 :                         check_raise_parameters(new);
    1948             : 
    1949        3944 :                         $$ = (PLpgSQL_stmt *)new;
    1950             :                     }
    1951             :                 ;
    1952             : 
    1953             : stmt_assert     : K_ASSERT
    1954          34 :                     {
    1955             :                         PLpgSQL_stmt_assert     *new;
    1956             :                         int tok;
    1957             : 
    1958          34 :                         new = palloc(sizeof(PLpgSQL_stmt_assert));
    1959             : 
    1960          34 :                         new->cmd_type    = PLPGSQL_STMT_ASSERT;
    1961          34 :                         new->lineno      = plpgsql_location_to_lineno(@1);
    1962          34 :                         new->stmtid      = ++plpgsql_curr_compile->nstatements;
    1963             : 
    1964          34 :                         new->cond = read_sql_expression2(',', ';',
    1965             :                                                          ", or ;",
    1966             :                                                          &tok);
    1967             : 
    1968          34 :                         if (tok == ',')
    1969           8 :                             new->message = read_sql_expression(';', ";");
    1970             :                         else
    1971          26 :                             new->message = NULL;
    1972             : 
    1973          34 :                         $$ = (PLpgSQL_stmt *) new;
    1974             :                     }
    1975             :                 ;
    1976             : 
    1977             : loop_body       : proc_sect K_END K_LOOP opt_label ';'
    1978             :                     {
    1979         834 :                         $$.stmts = $1;
    1980         834 :                         $$.end_label = $4;
    1981         834 :                         $$.end_label_location = @4;
    1982             :                     }
    1983             :                 ;
    1984             : 
    1985             : /*
    1986             :  * T_WORD+T_CWORD match any initial identifier that is not a known plpgsql
    1987             :  * variable.  (The composite case is probably a syntax error, but we'll let
    1988             :  * the core parser decide that.)  Normally, we should assume that such a
    1989             :  * word is a SQL statement keyword that isn't also a plpgsql keyword.
    1990             :  * However, if the next token is assignment or '[' or '.', it can't be a valid
    1991             :  * SQL statement, and what we're probably looking at is an intended variable
    1992             :  * assignment.  Give an appropriate complaint for that, instead of letting
    1993             :  * the core parser throw an unhelpful "syntax error".
    1994             :  */
    1995             : stmt_execsql    : K_IMPORT
    1996             :                     {
    1997           0 :                         $$ = make_execsql_stmt(K_IMPORT, @1);
    1998             :                     }
    1999             :                 | K_INSERT
    2000             :                     {
    2001         414 :                         $$ = make_execsql_stmt(K_INSERT, @1);
    2002             :                     }
    2003             :                 | T_WORD
    2004             :                     {
    2005             :                         int         tok;
    2006             : 
    2007        1258 :                         tok = yylex();
    2008        1258 :                         plpgsql_push_back_token(tok);
    2009        1258 :                         if (tok == '=' || tok == COLON_EQUALS ||
    2010        1258 :                             tok == '[' || tok == '.')
    2011           0 :                             word_is_not_variable(&($1), @1);
    2012        1258 :                         $$ = make_execsql_stmt(T_WORD, @1);
    2013             :                     }
    2014             :                 | T_CWORD
    2015             :                     {
    2016             :                         int         tok;
    2017             : 
    2018           4 :                         tok = yylex();
    2019           4 :                         plpgsql_push_back_token(tok);
    2020           4 :                         if (tok == '=' || tok == COLON_EQUALS ||
    2021           2 :                             tok == '[' || tok == '.')
    2022           4 :                             cword_is_not_variable(&($1), @1);
    2023           0 :                         $$ = make_execsql_stmt(T_CWORD, @1);
    2024             :                     }
    2025             :                 ;
    2026             : 
    2027             : stmt_dynexecute : K_EXECUTE
    2028         618 :                     {
    2029             :                         PLpgSQL_stmt_dynexecute *new;
    2030             :                         PLpgSQL_expr *expr;
    2031             :                         int endtoken;
    2032             : 
    2033         618 :                         expr = read_sql_construct(K_INTO, K_USING, ';',
    2034             :                                                   "INTO or USING or ;",
    2035             :                                                   RAW_PARSE_PLPGSQL_EXPR,
    2036             :                                                   true, true, true,
    2037             :                                                   NULL, &endtoken);
    2038             : 
    2039         618 :                         new = palloc(sizeof(PLpgSQL_stmt_dynexecute));
    2040         618 :                         new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;
    2041         618 :                         new->lineno = plpgsql_location_to_lineno(@1);
    2042         618 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    2043         618 :                         new->query = expr;
    2044         618 :                         new->into = false;
    2045         618 :                         new->strict = false;
    2046         618 :                         new->target = NULL;
    2047         618 :                         new->params = NIL;
    2048             : 
    2049             :                         /*
    2050             :                          * We loop to allow the INTO and USING clauses to
    2051             :                          * appear in either order, since people easily get
    2052             :                          * that wrong.  This coding also prevents "INTO foo"
    2053             :                          * from getting absorbed into a USING expression,
    2054             :                          * which is *really* confusing.
    2055             :                          */
    2056             :                         for (;;)
    2057             :                         {
    2058        1442 :                             if (endtoken == K_INTO)
    2059             :                             {
    2060         476 :                                 if (new->into)           /* multiple INTO */
    2061           0 :                                     yyerror("syntax error");
    2062         476 :                                 new->into = true;
    2063         476 :                                 read_into_target(&new->target, &new->strict);
    2064         476 :                                 endtoken = yylex();
    2065             :                             }
    2066         966 :                             else if (endtoken == K_USING)
    2067             :                             {
    2068         348 :                                 if (new->params)     /* multiple USING */
    2069           0 :                                     yyerror("syntax error");
    2070             :                                 do
    2071             :                                 {
    2072         692 :                                     expr = read_sql_construct(',', ';', K_INTO,
    2073             :                                                               ", or ; or INTO",
    2074             :                                                               RAW_PARSE_PLPGSQL_EXPR,
    2075             :                                                               true, true, true,
    2076             :                                                               NULL, &endtoken);
    2077         692 :                                     new->params = lappend(new->params, expr);
    2078         692 :                                 } while (endtoken == ',');
    2079             :                             }
    2080         618 :                             else if (endtoken == ';')
    2081         618 :                                 break;
    2082             :                             else
    2083           0 :                                 yyerror("syntax error");
    2084             :                         }
    2085             : 
    2086         618 :                         $$ = (PLpgSQL_stmt *)new;
    2087             :                     }
    2088             :                 ;
    2089             : 
    2090             : 
    2091             : stmt_open       : K_OPEN cursor_variable
    2092             :                     {
    2093             :                         PLpgSQL_stmt_open *new;
    2094             :                         int               tok;
    2095             : 
    2096          84 :                         new = palloc0(sizeof(PLpgSQL_stmt_open));
    2097          84 :                         new->cmd_type = PLPGSQL_STMT_OPEN;
    2098          84 :                         new->lineno = plpgsql_location_to_lineno(@1);
    2099          84 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    2100          84 :                         new->curvar = $2->dno;
    2101          84 :                         new->cursor_options = CURSOR_OPT_FAST_PLAN;
    2102             : 
    2103          84 :                         if ($2->cursor_explicit_expr == NULL)
    2104             :                         {
    2105             :                             /* be nice if we could use opt_scrollable here */
    2106          28 :                             tok = yylex();
    2107          28 :                             if (tok_is_keyword(tok, &yylval,
    2108             :                                                K_NO, "no"))
    2109             :                             {
    2110           0 :                                 tok = yylex();
    2111           0 :                                 if (tok_is_keyword(tok, &yylval,
    2112             :                                                    K_SCROLL, "scroll"))
    2113             :                                 {
    2114           0 :                                     new->cursor_options |= CURSOR_OPT_NO_SCROLL;
    2115           0 :                                     tok = yylex();
    2116             :                                 }
    2117             :                             }
    2118          28 :                             else if (tok_is_keyword(tok, &yylval,
    2119             :                                                     K_SCROLL, "scroll"))
    2120             :                             {
    2121          12 :                                 new->cursor_options |= CURSOR_OPT_SCROLL;
    2122          12 :                                 tok = yylex();
    2123             :                             }
    2124             : 
    2125          28 :                             if (tok != K_FOR)
    2126           0 :                                 yyerror("syntax error, expected \"FOR\"");
    2127             : 
    2128          28 :                             tok = yylex();
    2129          28 :                             if (tok == K_EXECUTE)
    2130             :                             {
    2131             :                                 int     endtoken;
    2132             : 
    2133          12 :                                 new->dynquery =
    2134          12 :                                     read_sql_expression2(K_USING, ';',
    2135             :                                                          "USING or ;",
    2136             :                                                          &endtoken);
    2137             : 
    2138             :                                 /* If we found "USING", collect argument(s) */
    2139          12 :                                 if (endtoken == K_USING)
    2140             :                                 {
    2141             :                                     PLpgSQL_expr *expr;
    2142             : 
    2143             :                                     do
    2144             :                                     {
    2145           4 :                                         expr = read_sql_expression2(',', ';',
    2146             :                                                                     ", or ;",
    2147             :                                                                     &endtoken);
    2148           4 :                                         new->params = lappend(new->params,
    2149             :                                                               expr);
    2150           4 :                                     } while (endtoken == ',');
    2151             :                                 }
    2152             :                             }
    2153             :                             else
    2154             :                             {
    2155          16 :                                 plpgsql_push_back_token(tok);
    2156          16 :                                 new->query = read_sql_stmt();
    2157             :                             }
    2158             :                         }
    2159             :                         else
    2160             :                         {
    2161             :                             /* predefined cursor query, so read args */
    2162          56 :                             new->argquery = read_cursor_args($2, ';');
    2163             :                         }
    2164             : 
    2165          68 :                         $$ = (PLpgSQL_stmt *)new;
    2166             :                     }
    2167             :                 ;
    2168             : 
    2169             : stmt_fetch      : K_FETCH opt_fetch_direction cursor_variable K_INTO
    2170          80 :                     {
    2171          80 :                         PLpgSQL_stmt_fetch *fetch = $2;
    2172             :                         PLpgSQL_variable *target;
    2173             : 
    2174             :                         /* We have already parsed everything through the INTO keyword */
    2175          80 :                         read_into_target(&target, NULL);
    2176             : 
    2177          80 :                         if (yylex() != ';')
    2178           0 :                             yyerror("syntax error");
    2179             : 
    2180             :                         /*
    2181             :                          * We don't allow multiple rows in PL/pgSQL's FETCH
    2182             :                          * statement, only in MOVE.
    2183             :                          */
    2184          80 :                         if (fetch->returns_multiple_rows)
    2185           0 :                             ereport(ERROR,
    2186             :                                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2187             :                                      errmsg("FETCH statement cannot return multiple rows"),
    2188             :                                      parser_errposition(@1)));
    2189             : 
    2190          80 :                         fetch->lineno = plpgsql_location_to_lineno(@1);
    2191          80 :                         fetch->target    = target;
    2192          80 :                         fetch->curvar    = $3->dno;
    2193          80 :                         fetch->is_move   = false;
    2194             : 
    2195          80 :                         $$ = (PLpgSQL_stmt *)fetch;
    2196             :                     }
    2197             :                 ;
    2198             : 
    2199             : stmt_move       : K_MOVE opt_fetch_direction cursor_variable ';'
    2200             :                     {
    2201          12 :                         PLpgSQL_stmt_fetch *fetch = $2;
    2202             : 
    2203          12 :                         fetch->lineno = plpgsql_location_to_lineno(@1);
    2204          12 :                         fetch->curvar    = $3->dno;
    2205          12 :                         fetch->is_move   = true;
    2206             : 
    2207          12 :                         $$ = (PLpgSQL_stmt *)fetch;
    2208             :                     }
    2209             :                 ;
    2210             : 
    2211             : opt_fetch_direction :
    2212             :                     {
    2213          92 :                         $$ = read_fetch_direction();
    2214             :                     }
    2215             :                 ;
    2216             : 
    2217             : stmt_close      : K_CLOSE cursor_variable ';'
    2218             :                     {
    2219             :                         PLpgSQL_stmt_close *new;
    2220             : 
    2221          44 :                         new = palloc(sizeof(PLpgSQL_stmt_close));
    2222          44 :                         new->cmd_type = PLPGSQL_STMT_CLOSE;
    2223          44 :                         new->lineno = plpgsql_location_to_lineno(@1);
    2224          44 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    2225          44 :                         new->curvar = $2->dno;
    2226             : 
    2227          44 :                         $$ = (PLpgSQL_stmt *)new;
    2228             :                     }
    2229             :                 ;
    2230             : 
    2231             : stmt_null       : K_NULL ';'
    2232             :                     {
    2233             :                         /* We do not bother building a node for NULL */
    2234          20 :                         $$ = NULL;
    2235             :                     }
    2236             :                 ;
    2237             : 
    2238             : stmt_commit     : K_COMMIT opt_transaction_chain ';'
    2239             :                     {
    2240             :                         PLpgSQL_stmt_commit *new;
    2241             : 
    2242          74 :                         new = palloc(sizeof(PLpgSQL_stmt_commit));
    2243          74 :                         new->cmd_type = PLPGSQL_STMT_COMMIT;
    2244          74 :                         new->lineno = plpgsql_location_to_lineno(@1);
    2245          74 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    2246          74 :                         new->chain = $2;
    2247             : 
    2248          74 :                         $$ = (PLpgSQL_stmt *)new;
    2249             :                     }
    2250             :                 ;
    2251             : 
    2252             : stmt_rollback   : K_ROLLBACK opt_transaction_chain ';'
    2253             :                     {
    2254             :                         PLpgSQL_stmt_rollback *new;
    2255             : 
    2256          32 :                         new = palloc(sizeof(PLpgSQL_stmt_rollback));
    2257          32 :                         new->cmd_type = PLPGSQL_STMT_ROLLBACK;
    2258          32 :                         new->lineno = plpgsql_location_to_lineno(@1);
    2259          32 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    2260          32 :                         new->chain = $2;
    2261             : 
    2262          32 :                         $$ = (PLpgSQL_stmt *)new;
    2263             :                     }
    2264             :                 ;
    2265             : 
    2266             : opt_transaction_chain:
    2267           4 :             K_AND K_CHAIN           { $$ = true; }
    2268           0 :             | K_AND K_NO K_CHAIN    { $$ = false; }
    2269         102 :             | /* EMPTY */           { $$ = false; }
    2270             :                 ;
    2271             : 
    2272             : 
    2273             : cursor_variable : T_DATUM
    2274             :                     {
    2275             :                         /*
    2276             :                          * In principle we should support a cursor_variable
    2277             :                          * that is an array element, but for now we don't, so
    2278             :                          * just throw an error if next token is '['.
    2279             :                          */
    2280         440 :                         if ($1.datum->dtype != PLPGSQL_DTYPE_VAR ||
    2281         220 :                             plpgsql_peek() == '[')
    2282           0 :                             ereport(ERROR,
    2283             :                                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    2284             :                                      errmsg("cursor variable must be a simple variable"),
    2285             :                                      parser_errposition(@1)));
    2286             : 
    2287         220 :                         if (((PLpgSQL_var *) $1.datum)->datatype->typoid != REFCURSOROID)
    2288           0 :                             ereport(ERROR,
    2289             :                                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    2290             :                                      errmsg("variable \"%s\" must be of type cursor or refcursor",
    2291             :                                             ((PLpgSQL_var *) $1.datum)->refname),
    2292             :                                      parser_errposition(@1)));
    2293         220 :                         $$ = (PLpgSQL_var *) $1.datum;
    2294             :                     }
    2295             :                 | T_WORD
    2296             :                     {
    2297             :                         /* just to give a better message than "syntax error" */
    2298           0 :                         word_is_not_variable(&($1), @1);
    2299             :                     }
    2300             :                 | T_CWORD
    2301             :                     {
    2302             :                         /* just to give a better message than "syntax error" */
    2303           0 :                         cword_is_not_variable(&($1), @1);
    2304             :                     }
    2305             :                 ;
    2306             : 
    2307             : exception_sect  :
    2308        4960 :                     { $$ = NULL; }
    2309             :                 | K_EXCEPTION
    2310             :                     {
    2311             :                         /*
    2312             :                          * We use a mid-rule action to add these
    2313             :                          * special variables to the namespace before
    2314             :                          * parsing the WHEN clauses themselves.  The
    2315             :                          * scope of the names extends to the end of the
    2316             :                          * current block.
    2317             :                          */
    2318         182 :                         int         lineno = plpgsql_location_to_lineno(@1);
    2319         182 :                         PLpgSQL_exception_block *new = palloc(sizeof(PLpgSQL_exception_block));
    2320             :                         PLpgSQL_variable *var;
    2321             : 
    2322         182 :                         var = plpgsql_build_variable("sqlstate", lineno,
    2323             :                                                      plpgsql_build_datatype(TEXTOID,
    2324             :                                                                             -1,
    2325         182 :                                                                             plpgsql_curr_compile->fn_input_collation,
    2326             :                                                                             NULL),
    2327             :                                                      true);
    2328         182 :                         var->isconst = true;
    2329         182 :                         new->sqlstate_varno = var->dno;
    2330             : 
    2331         182 :                         var = plpgsql_build_variable("sqlerrm", lineno,
    2332             :                                                      plpgsql_build_datatype(TEXTOID,
    2333             :                                                                             -1,
    2334         182 :                                                                             plpgsql_curr_compile->fn_input_collation,
    2335             :                                                                             NULL),
    2336             :                                                      true);
    2337         182 :                         var->isconst = true;
    2338         182 :                         new->sqlerrm_varno = var->dno;
    2339             : 
    2340         182 :                         $<exception_block>$ = new;
    2341             :                     }
    2342             :                     proc_exceptions
    2343             :                     {
    2344         182 :                         PLpgSQL_exception_block *new = $<exception_block>2;
    2345         182 :                         new->exc_list = $3;
    2346             : 
    2347         182 :                         $$ = new;
    2348             :                     }
    2349             :                 ;
    2350             : 
    2351             : proc_exceptions : proc_exceptions proc_exception
    2352             :                         {
    2353          10 :                             $$ = lappend($1, $2);
    2354             :                         }
    2355             :                 | proc_exception
    2356             :                         {
    2357         182 :                             $$ = list_make1($1);
    2358             :                         }
    2359             :                 ;
    2360             : 
    2361             : proc_exception  : K_WHEN proc_conditions K_THEN proc_sect
    2362             :                     {
    2363             :                         PLpgSQL_exception *new;
    2364             : 
    2365         192 :                         new = palloc0(sizeof(PLpgSQL_exception));
    2366         192 :                         new->lineno = plpgsql_location_to_lineno(@1);
    2367         192 :                         new->conditions = $2;
    2368         192 :                         new->action = $4;
    2369             : 
    2370         192 :                         $$ = new;
    2371             :                     }
    2372             :                 ;
    2373             : 
    2374             : proc_conditions : proc_conditions K_OR proc_condition
    2375             :                         {
    2376             :                             PLpgSQL_condition   *old;
    2377             : 
    2378          14 :                             for (old = $1; old->next != NULL; old = old->next)
    2379             :                                 /* skip */ ;
    2380          10 :                             old->next = $3;
    2381          10 :                             $$ = $1;
    2382             :                         }
    2383             :                 | proc_condition
    2384             :                         {
    2385         192 :                             $$ = $1;
    2386             :                         }
    2387             :                 ;
    2388             : 
    2389             : proc_condition  : any_identifier
    2390             :                         {
    2391         202 :                             if (strcmp($1, "sqlstate") != 0)
    2392             :                             {
    2393         182 :                                 $$ = plpgsql_parse_err_condition($1);
    2394             :                             }
    2395             :                             else
    2396             :                             {
    2397             :                                 PLpgSQL_condition *new;
    2398             :                                 char   *sqlstatestr;
    2399             : 
    2400             :                                 /* next token should be a string literal */
    2401          20 :                                 if (yylex() != SCONST)
    2402           0 :                                     yyerror("syntax error");
    2403          20 :                                 sqlstatestr = yylval.str;
    2404             : 
    2405          20 :                                 if (strlen(sqlstatestr) != 5)
    2406           0 :                                     yyerror("invalid SQLSTATE code");
    2407          20 :                                 if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5)
    2408           0 :                                     yyerror("invalid SQLSTATE code");
    2409             : 
    2410          20 :                                 new = palloc(sizeof(PLpgSQL_condition));
    2411          20 :                                 new->sqlerrstate =
    2412          20 :                                     MAKE_SQLSTATE(sqlstatestr[0],
    2413             :                                                   sqlstatestr[1],
    2414             :                                                   sqlstatestr[2],
    2415             :                                                   sqlstatestr[3],
    2416             :                                                   sqlstatestr[4]);
    2417          20 :                                 new->condname = sqlstatestr;
    2418          20 :                                 new->next = NULL;
    2419             : 
    2420          20 :                                 $$ = new;
    2421             :                             }
    2422             :                         }
    2423             :                 ;
    2424             : 
    2425             : expr_until_semi :
    2426          68 :                     { $$ = read_sql_expression(';', ";"); }
    2427             :                 ;
    2428             : 
    2429             : expr_until_then :
    2430        4338 :                     { $$ = read_sql_expression(K_THEN, "THEN"); }
    2431             :                 ;
    2432             : 
    2433             : expr_until_loop :
    2434         102 :                     { $$ = read_sql_expression(K_LOOP, "LOOP"); }
    2435             :                 ;
    2436             : 
    2437             : opt_block_label :
    2438             :                     {
    2439        5202 :                         plpgsql_ns_push(NULL, PLPGSQL_LABEL_BLOCK);
    2440        5202 :                         $$ = NULL;
    2441             :                     }
    2442             :                 | LESS_LESS any_identifier GREATER_GREATER
    2443             :                     {
    2444          52 :                         plpgsql_ns_push($2, PLPGSQL_LABEL_BLOCK);
    2445          52 :                         $$ = $2;
    2446             :                     }
    2447             :                 ;
    2448             : 
    2449             : opt_loop_label  :
    2450             :                     {
    2451         824 :                         plpgsql_ns_push(NULL, PLPGSQL_LABEL_LOOP);
    2452         824 :                         $$ = NULL;
    2453             :                     }
    2454             :                 | LESS_LESS any_identifier GREATER_GREATER
    2455             :                     {
    2456          30 :                         plpgsql_ns_push($2, PLPGSQL_LABEL_LOOP);
    2457          30 :                         $$ = $2;
    2458             :                     }
    2459             :                 ;
    2460             : 
    2461             : opt_label   :
    2462             :                     {
    2463        6058 :                         $$ = NULL;
    2464             :                     }
    2465             :                 | any_identifier
    2466             :                     {
    2467             :                         /* label validity will be checked by outer production */
    2468          42 :                         $$ = $1;
    2469             :                     }
    2470             :                 ;
    2471             : 
    2472             : opt_exitcond    : ';'
    2473          56 :                     { $$ = NULL; }
    2474             :                 | K_WHEN expr_until_semi
    2475          68 :                     { $$ = $2; }
    2476             :                 ;
    2477             : 
    2478             : /*
    2479             :  * need to allow DATUM because scanner will have tried to resolve as variable
    2480             :  */
    2481             : any_identifier  : T_WORD
    2482             :                     {
    2483         306 :                         $$ = $1.ident;
    2484             :                     }
    2485             :                 | unreserved_keyword
    2486             :                     {
    2487           0 :                         $$ = pstrdup($1);
    2488             :                     }
    2489             :                 | T_DATUM
    2490             :                     {
    2491          20 :                         if ($1.ident == NULL) /* composite name not OK */
    2492           0 :                             yyerror("syntax error");
    2493          20 :                         $$ = $1.ident;
    2494             :                     }
    2495             :                 ;
    2496             : 
    2497             : unreserved_keyword  :
    2498             :                 K_ABSOLUTE
    2499             :                 | K_ALIAS
    2500             :                 | K_AND
    2501             :                 | K_ARRAY
    2502             :                 | K_ASSERT
    2503             :                 | K_BACKWARD
    2504             :                 | K_CALL
    2505             :                 | K_CHAIN
    2506             :                 | K_CLOSE
    2507             :                 | K_COLLATE
    2508             :                 | K_COLUMN
    2509             :                 | K_COLUMN_NAME
    2510             :                 | K_COMMIT
    2511             :                 | K_CONSTANT
    2512             :                 | K_CONSTRAINT
    2513             :                 | K_CONSTRAINT_NAME
    2514             :                 | K_CONTINUE
    2515             :                 | K_CURRENT
    2516             :                 | K_CURSOR
    2517             :                 | K_DATATYPE
    2518             :                 | K_DEBUG
    2519             :                 | K_DEFAULT
    2520             :                 | K_DETAIL
    2521             :                 | K_DIAGNOSTICS
    2522             :                 | K_DO
    2523             :                 | K_DUMP
    2524             :                 | K_ELSIF
    2525             :                 | K_ERRCODE
    2526             :                 | K_ERROR
    2527             :                 | K_EXCEPTION
    2528             :                 | K_EXIT
    2529             :                 | K_FETCH
    2530             :                 | K_FIRST
    2531             :                 | K_FORWARD
    2532             :                 | K_GET
    2533             :                 | K_HINT
    2534             :                 | K_IMPORT
    2535             :                 | K_INFO
    2536             :                 | K_INSERT
    2537             :                 | K_IS
    2538             :                 | K_LAST
    2539             :                 | K_LOG
    2540             :                 | K_MESSAGE
    2541             :                 | K_MESSAGE_TEXT
    2542             :                 | K_MOVE
    2543             :                 | K_NEXT
    2544             :                 | K_NO
    2545             :                 | K_NOTICE
    2546             :                 | K_OPEN
    2547             :                 | K_OPTION
    2548             :                 | K_PERFORM
    2549             :                 | K_PG_CONTEXT
    2550             :                 | K_PG_DATATYPE_NAME
    2551             :                 | K_PG_EXCEPTION_CONTEXT
    2552             :                 | K_PG_EXCEPTION_DETAIL
    2553             :                 | K_PG_EXCEPTION_HINT
    2554             :                 | K_PRINT_STRICT_PARAMS
    2555             :                 | K_PRIOR
    2556             :                 | K_QUERY
    2557             :                 | K_RAISE
    2558             :                 | K_RELATIVE
    2559             :                 | K_RETURN
    2560             :                 | K_RETURNED_SQLSTATE
    2561             :                 | K_REVERSE
    2562             :                 | K_ROLLBACK
    2563             :                 | K_ROW_COUNT
    2564             :                 | K_ROWTYPE
    2565             :                 | K_SCHEMA
    2566             :                 | K_SCHEMA_NAME
    2567             :                 | K_SCROLL
    2568             :                 | K_SLICE
    2569             :                 | K_SQLSTATE
    2570             :                 | K_STACKED
    2571             :                 | K_TABLE
    2572             :                 | K_TABLE_NAME
    2573             :                 | K_TYPE
    2574             :                 | K_USE_COLUMN
    2575             :                 | K_USE_VARIABLE
    2576             :                 | K_VARIABLE_CONFLICT
    2577             :                 | K_WARNING
    2578             :                 ;
    2579             : 
    2580             : %%
    2581             : 
    2582             : /*
    2583             :  * Check whether a token represents an "unreserved keyword".
    2584             :  * We have various places where we want to recognize a keyword in preference
    2585             :  * to a variable name, but not reserve that keyword in other contexts.
    2586             :  * Hence, this kluge.
    2587             :  */
    2588             : static bool
    2589       24120 : tok_is_keyword(int token, union YYSTYPE *lval,
    2590             :                int kw_token, const char *kw_str)
    2591             : {
    2592       24120 :     if (token == kw_token)
    2593             :     {
    2594             :         /* Normal case, was recognized by scanner (no conflicting variable) */
    2595        4606 :         return true;
    2596             :     }
    2597       19514 :     else if (token == T_DATUM)
    2598             :     {
    2599             :         /*
    2600             :          * It's a variable, so recheck the string name.  Note we will not
    2601             :          * match composite names (hence an unreserved word followed by "."
    2602             :          * will not be recognized).
    2603             :          */
    2604        6228 :         if (!lval->wdatum.quoted && lval->wdatum.ident != NULL &&
    2605        6108 :             strcmp(lval->wdatum.ident, kw_str) == 0)
    2606           4 :             return true;
    2607             :     }
    2608       19510 :     return false;               /* not the keyword */
    2609             : }
    2610             : 
    2611             : /*
    2612             :  * Convenience routine to complain when we expected T_DATUM and got T_WORD,
    2613             :  * ie, unrecognized variable.
    2614             :  */
    2615             : static void
    2616           0 : word_is_not_variable(PLword *word, int location)
    2617             : {
    2618           0 :     ereport(ERROR,
    2619             :             (errcode(ERRCODE_SYNTAX_ERROR),
    2620             :              errmsg("\"%s\" is not a known variable",
    2621             :                     word->ident),
    2622             :              parser_errposition(location)));
    2623             : }
    2624             : 
    2625             : /* Same, for a CWORD */
    2626             : static void
    2627           4 : cword_is_not_variable(PLcword *cword, int location)
    2628             : {
    2629           4 :     ereport(ERROR,
    2630             :             (errcode(ERRCODE_SYNTAX_ERROR),
    2631             :              errmsg("\"%s\" is not a known variable",
    2632             :                     NameListToString(cword->idents)),
    2633             :              parser_errposition(location)));
    2634             : }
    2635             : 
    2636             : /*
    2637             :  * Convenience routine to complain when we expected T_DATUM and got
    2638             :  * something else.  "tok" must be the current token, since we also
    2639             :  * look at yylval and yylloc.
    2640             :  */
    2641             : static void
    2642           0 : current_token_is_not_variable(int tok)
    2643             : {
    2644           0 :     if (tok == T_WORD)
    2645           0 :         word_is_not_variable(&(yylval.word), yylloc);
    2646           0 :     else if (tok == T_CWORD)
    2647           0 :         cword_is_not_variable(&(yylval.cword), yylloc);
    2648             :     else
    2649           0 :         yyerror("syntax error");
    2650           0 : }
    2651             : 
    2652             : /* Convenience routine to read an expression with one possible terminator */
    2653             : static PLpgSQL_expr *
    2654        7018 : read_sql_expression(int until, const char *expected)
    2655             : {
    2656        7018 :     return read_sql_construct(until, 0, 0, expected,
    2657             :                               RAW_PARSE_PLPGSQL_EXPR,
    2658             :                               true, true, true, NULL, NULL);
    2659             : }
    2660             : 
    2661             : /* Convenience routine to read an expression with two possible terminators */
    2662             : static PLpgSQL_expr *
    2663         724 : read_sql_expression2(int until, int until2, const char *expected,
    2664             :                      int *endtoken)
    2665             : {
    2666         724 :     return read_sql_construct(until, until2, 0, expected,
    2667             :                               RAW_PARSE_PLPGSQL_EXPR,
    2668             :                               true, true, true, NULL, endtoken);
    2669             : }
    2670             : 
    2671             : /* Convenience routine to read a SQL statement that must end with ';' */
    2672             : static PLpgSQL_expr *
    2673         216 : read_sql_stmt(void)
    2674             : {
    2675         216 :     return read_sql_construct(';', 0, 0, ";",
    2676             :                               RAW_PARSE_DEFAULT,
    2677             :                               false, true, true, NULL, NULL);
    2678             : }
    2679             : 
    2680             : /*
    2681             :  * Read a SQL construct and build a PLpgSQL_expr for it.
    2682             :  *
    2683             :  * until:       token code for expected terminator
    2684             :  * until2:      token code for alternate terminator (pass 0 if none)
    2685             :  * until3:      token code for another alternate terminator (pass 0 if none)
    2686             :  * expected:    text to use in complaining that terminator was not found
    2687             :  * parsemode:   raw_parser() mode to use
    2688             :  * isexpression: whether to say we're reading an "expression" or a "statement"
    2689             :  * valid_sql:   whether to check the syntax of the expr
    2690             :  * trim:        trim trailing whitespace
    2691             :  * startloc:    if not NULL, location of first token is stored at *startloc
    2692             :  * endtoken:    if not NULL, ending token is stored at *endtoken
    2693             :  *              (this is only interesting if until2 or until3 isn't zero)
    2694             :  */
    2695             : static PLpgSQL_expr *
    2696       26258 : read_sql_construct(int until,
    2697             :                    int until2,
    2698             :                    int until3,
    2699             :                    const char *expected,
    2700             :                    RawParseMode parsemode,
    2701             :                    bool isexpression,
    2702             :                    bool valid_sql,
    2703             :                    bool trim,
    2704             :                    int *startloc,
    2705             :                    int *endtoken)
    2706             : {
    2707             :     int                 tok;
    2708             :     StringInfoData      ds;
    2709             :     IdentifierLookup    save_IdentifierLookup;
    2710       26258 :     int                 startlocation = -1;
    2711       26258 :     int                 parenlevel = 0;
    2712             :     PLpgSQL_expr        *expr;
    2713             : 
    2714       26258 :     initStringInfo(&ds);
    2715             : 
    2716             :     /* special lookup mode for identifiers within the SQL text */
    2717       26258 :     save_IdentifierLookup = plpgsql_IdentifierLookup;
    2718       26258 :     plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
    2719             : 
    2720             :     for (;;)
    2721             :     {
    2722      107170 :         tok = yylex();
    2723      107170 :         if (startlocation < 0)           /* remember loc of first token */
    2724       26258 :             startlocation = yylloc;
    2725      107170 :         if (tok == until && parenlevel == 0)
    2726       21950 :             break;
    2727       85220 :         if (tok == until2 && parenlevel == 0)
    2728        4150 :             break;
    2729       81070 :         if (tok == until3 && parenlevel == 0)
    2730         158 :             break;
    2731       80912 :         if (tok == '(' || tok == '[')
    2732        5512 :             parenlevel++;
    2733       75400 :         else if (tok == ')' || tok == ']')
    2734             :         {
    2735        5512 :             parenlevel--;
    2736        5512 :             if (parenlevel < 0)
    2737           0 :                 yyerror("mismatched parentheses");
    2738             :         }
    2739             :         /*
    2740             :          * End of function definition is an error, and we don't expect to
    2741             :          * hit a semicolon either (unless it's the until symbol, in which
    2742             :          * case we should have fallen out above).
    2743             :          */
    2744       80912 :         if (tok == 0 || tok == ';')
    2745             :         {
    2746           0 :             if (parenlevel != 0)
    2747           0 :                 yyerror("mismatched parentheses");
    2748           0 :             if (isexpression)
    2749           0 :                 ereport(ERROR,
    2750             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    2751             :                          errmsg("missing \"%s\" at end of SQL expression",
    2752             :                                 expected),
    2753             :                          parser_errposition(yylloc)));
    2754             :             else
    2755           0 :                 ereport(ERROR,
    2756             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    2757             :                          errmsg("missing \"%s\" at end of SQL statement",
    2758             :                                 expected),
    2759             :                          parser_errposition(yylloc)));
    2760             :         }
    2761             :     }
    2762             : 
    2763       26258 :     plpgsql_IdentifierLookup = save_IdentifierLookup;
    2764             : 
    2765       26258 :     if (startloc)
    2766         886 :         *startloc = startlocation;
    2767       26258 :     if (endtoken)
    2768       12406 :         *endtoken = tok;
    2769             : 
    2770             :     /* give helpful complaint about empty input */
    2771       26258 :     if (startlocation >= yylloc)
    2772             :     {
    2773           4 :         if (isexpression)
    2774           4 :             yyerror("missing expression");
    2775             :         else
    2776           0 :             yyerror("missing SQL statement");
    2777             :     }
    2778             : 
    2779       26254 :     plpgsql_append_source_text(&ds, startlocation, yylloc);
    2780             : 
    2781             :     /* trim any trailing whitespace, for neatness */
    2782       26254 :     if (trim)
    2783             :     {
    2784       32960 :         while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1]))
    2785        6790 :             ds.data[--ds.len] = '\0';
    2786             :     }
    2787             : 
    2788       26254 :     expr = palloc0(sizeof(PLpgSQL_expr));
    2789       26254 :     expr->query          = pstrdup(ds.data);
    2790       26254 :     expr->parseMode      = parsemode;
    2791       26254 :     expr->plan           = NULL;
    2792       26254 :     expr->paramnos       = NULL;
    2793       26254 :     expr->target_param   = -1;
    2794       26254 :     expr->ns         = plpgsql_ns_top();
    2795       26254 :     pfree(ds.data);
    2796             : 
    2797       26254 :     if (valid_sql)
    2798       25368 :         check_sql_expr(expr->query, expr->parseMode, startlocation);
    2799             : 
    2800       26254 :     return expr;
    2801             : }
    2802             : 
    2803             : static PLpgSQL_type *
    2804        4112 : read_datatype(int tok)
    2805             : {
    2806             :     StringInfoData      ds;
    2807             :     char               *type_name;
    2808             :     int                 startlocation;
    2809             :     PLpgSQL_type        *result;
    2810        4112 :     int                 parenlevel = 0;
    2811             : 
    2812             :     /* Should only be called while parsing DECLARE sections */
    2813             :     Assert(plpgsql_IdentifierLookup == IDENTIFIER_LOOKUP_DECLARE);
    2814             : 
    2815             :     /* Often there will be a lookahead token, but if not, get one */
    2816        4112 :     if (tok == YYEMPTY)
    2817         110 :         tok = yylex();
    2818             : 
    2819        4112 :     startlocation = yylloc;
    2820             : 
    2821             :     /*
    2822             :      * If we have a simple or composite identifier, check for %TYPE
    2823             :      * and %ROWTYPE constructs.
    2824             :      */
    2825        4112 :     if (tok == T_WORD)
    2826             :     {
    2827        4080 :         char   *dtname = yylval.word.ident;
    2828             : 
    2829        4080 :         tok = yylex();
    2830        4080 :         if (tok == '%')
    2831             :         {
    2832          40 :             tok = yylex();
    2833          40 :             if (tok_is_keyword(tok, &yylval,
    2834             :                                K_TYPE, "type"))
    2835             :             {
    2836           0 :                 result = plpgsql_parse_wordtype(dtname);
    2837           0 :                 if (result)
    2838           0 :                     return result;
    2839             :             }
    2840          40 :             else if (tok_is_keyword(tok, &yylval,
    2841             :                                     K_ROWTYPE, "rowtype"))
    2842             :             {
    2843          40 :                 result = plpgsql_parse_wordrowtype(dtname);
    2844          40 :                 if (result)
    2845          40 :                     return result;
    2846             :             }
    2847             :         }
    2848             :     }
    2849          32 :     else if (plpgsql_token_is_unreserved_keyword(tok))
    2850             :     {
    2851           0 :         char   *dtname = pstrdup(yylval.keyword);
    2852             : 
    2853           0 :         tok = yylex();
    2854           0 :         if (tok == '%')
    2855             :         {
    2856           0 :             tok = yylex();
    2857           0 :             if (tok_is_keyword(tok, &yylval,
    2858             :                                K_TYPE, "type"))
    2859             :             {
    2860           0 :                 result = plpgsql_parse_wordtype(dtname);
    2861           0 :                 if (result)
    2862           0 :                     return result;
    2863             :             }
    2864           0 :             else if (tok_is_keyword(tok, &yylval,
    2865             :                                     K_ROWTYPE, "rowtype"))
    2866             :             {
    2867           0 :                 result = plpgsql_parse_wordrowtype(dtname);
    2868           0 :                 if (result)
    2869           0 :                     return result;
    2870             :             }
    2871             :         }
    2872             :     }
    2873          32 :     else if (tok == T_CWORD)
    2874             :     {
    2875          32 :         List   *dtnames = yylval.cword.idents;
    2876             : 
    2877          32 :         tok = yylex();
    2878          32 :         if (tok == '%')
    2879             :         {
    2880          16 :             tok = yylex();
    2881          16 :             if (tok_is_keyword(tok, &yylval,
    2882             :                                K_TYPE, "type"))
    2883             :             {
    2884          16 :                 result = plpgsql_parse_cwordtype(dtnames);
    2885          16 :                 if (result)
    2886          16 :                     return result;
    2887             :             }
    2888           0 :             else if (tok_is_keyword(tok, &yylval,
    2889             :                                     K_ROWTYPE, "rowtype"))
    2890             :             {
    2891           0 :                 result = plpgsql_parse_cwordrowtype(dtnames);
    2892           0 :                 if (result)
    2893           0 :                     return result;
    2894             :             }
    2895             :         }
    2896             :     }
    2897             : 
    2898        4688 :     while (tok != ';')
    2899             :     {
    2900        1172 :         if (tok == 0)
    2901             :         {
    2902           0 :             if (parenlevel != 0)
    2903           0 :                 yyerror("mismatched parentheses");
    2904             :             else
    2905           0 :                 yyerror("incomplete data type declaration");
    2906             :         }
    2907             :         /* Possible followers for datatype in a declaration */
    2908        1172 :         if (tok == K_COLLATE || tok == K_NOT ||
    2909        1054 :             tok == '=' || tok == COLON_EQUALS || tok == K_DEFAULT)
    2910             :             break;
    2911             :         /* Possible followers for datatype in a cursor_arg list */
    2912         728 :         if ((tok == ',' || tok == ')') && parenlevel == 0)
    2913          96 :             break;
    2914         632 :         if (tok == '(')
    2915          76 :             parenlevel++;
    2916         556 :         else if (tok == ')')
    2917          76 :             parenlevel--;
    2918             : 
    2919         632 :         tok = yylex();
    2920             :     }
    2921             : 
    2922             :     /* set up ds to contain complete typename text */
    2923        4056 :     initStringInfo(&ds);
    2924        4056 :     plpgsql_append_source_text(&ds, startlocation, yylloc);
    2925        4056 :     type_name = ds.data;
    2926             : 
    2927        4056 :     if (type_name[0] == '\0')
    2928           0 :         yyerror("missing data type declaration");
    2929             : 
    2930        4056 :     result = parse_datatype(type_name, startlocation);
    2931             : 
    2932        4054 :     pfree(ds.data);
    2933             : 
    2934        4054 :     plpgsql_push_back_token(tok);
    2935             : 
    2936        4054 :     return result;
    2937             : }
    2938             : 
    2939             : static PLpgSQL_stmt *
    2940        1672 : make_execsql_stmt(int firsttoken, int location)
    2941             : {
    2942             :     StringInfoData      ds;
    2943             :     IdentifierLookup    save_IdentifierLookup;
    2944             :     PLpgSQL_stmt_execsql *execsql;
    2945             :     PLpgSQL_expr        *expr;
    2946        1672 :     PLpgSQL_variable    *target = NULL;
    2947             :     int                 tok;
    2948             :     int                 prev_tok;
    2949        1672 :     bool                have_into = false;
    2950        1672 :     bool                have_strict = false;
    2951        1672 :     int                 into_start_loc = -1;
    2952        1672 :     int                 into_end_loc = -1;
    2953             : 
    2954        1672 :     initStringInfo(&ds);
    2955             : 
    2956             :     /* special lookup mode for identifiers within the SQL text */
    2957        1672 :     save_IdentifierLookup = plpgsql_IdentifierLookup;
    2958        1672 :     plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
    2959             : 
    2960             :     /*
    2961             :      * Scan to the end of the SQL command.  Identify any INTO-variables
    2962             :      * clause lurking within it, and parse that via read_into_target().
    2963             :      *
    2964             :      * Because INTO is sometimes used in the main SQL grammar, we have to be
    2965             :      * careful not to take any such usage of INTO as a PL/pgSQL INTO clause.
    2966             :      * There are currently three such cases:
    2967             :      *
    2968             :      * 1. SELECT ... INTO.  We don't care, we just override that with the
    2969             :      * PL/pgSQL definition.
    2970             :      *
    2971             :      * 2. INSERT INTO.  This is relatively easy to recognize since the words
    2972             :      * must appear adjacently; but we can't assume INSERT starts the command,
    2973             :      * because it can appear in CREATE RULE or WITH.  Unfortunately, INSERT is
    2974             :      * *not* fully reserved, so that means there is a chance of a false match;
    2975             :      * but it's not very likely.
    2976             :      *
    2977             :      * 3. IMPORT FOREIGN SCHEMA ... INTO.  This is not allowed in CREATE RULE
    2978             :      * or WITH, so we just check for IMPORT as the command's first token.
    2979             :      * (If IMPORT FOREIGN SCHEMA returned data someone might wish to capture
    2980             :      * with an INTO-variables clause, we'd have to work much harder here.)
    2981             :      *
    2982             :      * Fortunately, INTO is a fully reserved word in the main grammar, so
    2983             :      * at least we need not worry about it appearing as an identifier.
    2984             :      *
    2985             :      * Any future additional uses of INTO in the main grammar will doubtless
    2986             :      * break this logic again ... beware!
    2987             :      */
    2988        1672 :     tok = firsttoken;
    2989             :     for (;;)
    2990             :     {
    2991       16346 :         prev_tok = tok;
    2992       18018 :         tok = yylex();
    2993       18018 :         if (have_into && into_end_loc < 0)
    2994         510 :             into_end_loc = yylloc;      /* token after the INTO part */
    2995       18018 :         if (tok == ';')
    2996        1672 :             break;
    2997       16346 :         if (tok == 0)
    2998           0 :             yyerror("unexpected end of function definition");
    2999       16346 :         if (tok == K_INTO)
    3000             :         {
    3001         924 :             if (prev_tok == K_INSERT)
    3002         414 :                 continue;       /* INSERT INTO is not an INTO-target */
    3003         510 :             if (firsttoken == K_IMPORT)
    3004           0 :                 continue;       /* IMPORT ... INTO is not an INTO-target */
    3005         510 :             if (have_into)
    3006           0 :                 yyerror("INTO specified more than once");
    3007         510 :             have_into = true;
    3008         510 :             into_start_loc = yylloc;
    3009         510 :             plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
    3010         510 :             read_into_target(&target, &have_strict);
    3011         510 :             plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
    3012             :         }
    3013             :     }
    3014             : 
    3015        1672 :     plpgsql_IdentifierLookup = save_IdentifierLookup;
    3016             : 
    3017        1672 :     if (have_into)
    3018             :     {
    3019             :         /*
    3020             :          * Insert an appropriate number of spaces corresponding to the
    3021             :          * INTO text, so that locations within the redacted SQL statement
    3022             :          * still line up with those in the original source text.
    3023             :          */
    3024         510 :         plpgsql_append_source_text(&ds, location, into_start_loc);
    3025         510 :         appendStringInfoSpaces(&ds, into_end_loc - into_start_loc);
    3026         510 :         plpgsql_append_source_text(&ds, into_end_loc, yylloc);
    3027             :     }
    3028             :     else
    3029        1162 :         plpgsql_append_source_text(&ds, location, yylloc);
    3030             : 
    3031             :     /* trim any trailing whitespace, for neatness */
    3032        3266 :     while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1]))
    3033        1594 :         ds.data[--ds.len] = '\0';
    3034             : 
    3035        1672 :     expr = palloc0(sizeof(PLpgSQL_expr));
    3036        1672 :     expr->query          = pstrdup(ds.data);
    3037        1672 :     expr->parseMode      = RAW_PARSE_DEFAULT;
    3038        1672 :     expr->plan           = NULL;
    3039        1672 :     expr->paramnos       = NULL;
    3040        1672 :     expr->target_param   = -1;
    3041        1672 :     expr->ns         = plpgsql_ns_top();
    3042        1672 :     pfree(ds.data);
    3043             : 
    3044        1672 :     check_sql_expr(expr->query, expr->parseMode, location);
    3045             : 
    3046        1668 :     execsql = palloc0(sizeof(PLpgSQL_stmt_execsql));
    3047        1668 :     execsql->cmd_type = PLPGSQL_STMT_EXECSQL;
    3048        1668 :     execsql->lineno  = plpgsql_location_to_lineno(location);
    3049        1668 :     execsql->stmtid  = ++plpgsql_curr_compile->nstatements;
    3050        1668 :     execsql->sqlstmt = expr;
    3051        1668 :     execsql->into     = have_into;
    3052        1668 :     execsql->strict   = have_strict;
    3053        1668 :     execsql->target   = target;
    3054             : 
    3055        1668 :     return (PLpgSQL_stmt *) execsql;
    3056             : }
    3057             : 
    3058             : 
    3059             : /*
    3060             :  * Read FETCH or MOVE direction clause (everything through FROM/IN).
    3061             :  */
    3062             : static PLpgSQL_stmt_fetch *
    3063          92 : read_fetch_direction(void)
    3064             : {
    3065             :     PLpgSQL_stmt_fetch *fetch;
    3066             :     int         tok;
    3067          92 :     bool        check_FROM = true;
    3068             : 
    3069             :     /*
    3070             :      * We create the PLpgSQL_stmt_fetch struct here, but only fill in
    3071             :      * the fields arising from the optional direction clause
    3072             :      */
    3073          92 :     fetch = (PLpgSQL_stmt_fetch *) palloc0(sizeof(PLpgSQL_stmt_fetch));
    3074          92 :     fetch->cmd_type = PLPGSQL_STMT_FETCH;
    3075          92 :     fetch->stmtid    = ++plpgsql_curr_compile->nstatements;
    3076             :     /* set direction defaults: */
    3077          92 :     fetch->direction = FETCH_FORWARD;
    3078          92 :     fetch->how_many  = 1;
    3079          92 :     fetch->expr       = NULL;
    3080          92 :     fetch->returns_multiple_rows = false;
    3081             : 
    3082          92 :     tok = yylex();
    3083          92 :     if (tok == 0)
    3084           0 :         yyerror("unexpected end of function definition");
    3085             : 
    3086          92 :     if (tok_is_keyword(tok, &yylval,
    3087             :                        K_NEXT, "next"))
    3088             :     {
    3089             :         /* use defaults */
    3090             :     }
    3091          84 :     else if (tok_is_keyword(tok, &yylval,
    3092             :                             K_PRIOR, "prior"))
    3093             :     {
    3094          12 :         fetch->direction = FETCH_BACKWARD;
    3095             :     }
    3096          72 :     else if (tok_is_keyword(tok, &yylval,
    3097             :                             K_FIRST, "first"))
    3098             :     {
    3099           0 :         fetch->direction = FETCH_ABSOLUTE;
    3100             :     }
    3101          72 :     else if (tok_is_keyword(tok, &yylval,
    3102             :                             K_LAST, "last"))
    3103             :     {
    3104          20 :         fetch->direction = FETCH_ABSOLUTE;
    3105          20 :         fetch->how_many  = -1;
    3106             :     }
    3107          52 :     else if (tok_is_keyword(tok, &yylval,
    3108             :                             K_ABSOLUTE, "absolute"))
    3109             :     {
    3110           0 :         fetch->direction = FETCH_ABSOLUTE;
    3111           0 :         fetch->expr = read_sql_expression2(K_FROM, K_IN,
    3112             :                                            "FROM or IN",
    3113             :                                            NULL);
    3114           0 :         check_FROM = false;
    3115             :     }
    3116          52 :     else if (tok_is_keyword(tok, &yylval,
    3117             :                             K_RELATIVE, "relative"))
    3118             :     {
    3119          12 :         fetch->direction = FETCH_RELATIVE;
    3120          12 :         fetch->expr = read_sql_expression2(K_FROM, K_IN,
    3121             :                                            "FROM or IN",
    3122             :                                            NULL);
    3123          12 :         check_FROM = false;
    3124             :     }
    3125          40 :     else if (tok_is_keyword(tok, &yylval,
    3126             :                             K_ALL, "all"))
    3127             :     {
    3128           0 :         fetch->how_many = FETCH_ALL;
    3129           0 :         fetch->returns_multiple_rows = true;
    3130             :     }
    3131          40 :     else if (tok_is_keyword(tok, &yylval,
    3132             :                             K_FORWARD, "forward"))
    3133             :     {
    3134           4 :         complete_direction(fetch, &check_FROM);
    3135             :     }
    3136          36 :     else if (tok_is_keyword(tok, &yylval,
    3137             :                             K_BACKWARD, "backward"))
    3138             :     {
    3139           8 :         fetch->direction = FETCH_BACKWARD;
    3140           8 :         complete_direction(fetch, &check_FROM);
    3141             :     }
    3142          28 :     else if (tok == K_FROM || tok == K_IN)
    3143             :     {
    3144             :         /* empty direction */
    3145           0 :         check_FROM = false;
    3146             :     }
    3147          28 :     else if (tok == T_DATUM)
    3148             :     {
    3149             :         /* Assume there's no direction clause and tok is a cursor name */
    3150          28 :         plpgsql_push_back_token(tok);
    3151          28 :         check_FROM = false;
    3152             :     }
    3153             :     else
    3154             :     {
    3155             :         /*
    3156             :          * Assume it's a count expression with no preceding keyword.
    3157             :          * Note: we allow this syntax because core SQL does, but we don't
    3158             :          * document it because of the ambiguity with the omitted-direction
    3159             :          * case.  For instance, "MOVE n IN c" will fail if n is a variable.
    3160             :          * Perhaps this can be improved someday, but it's hardly worth a
    3161             :          * lot of work.
    3162             :          */
    3163           0 :         plpgsql_push_back_token(tok);
    3164           0 :         fetch->expr = read_sql_expression2(K_FROM, K_IN,
    3165             :                                            "FROM or IN",
    3166             :                                            NULL);
    3167           0 :         fetch->returns_multiple_rows = true;
    3168           0 :         check_FROM = false;
    3169             :     }
    3170             : 
    3171             :     /* check FROM or IN keyword after direction's specification */
    3172          92 :     if (check_FROM)
    3173             :     {
    3174          44 :         tok = yylex();
    3175          44 :         if (tok != K_FROM && tok != K_IN)
    3176           0 :             yyerror("expected FROM or IN");
    3177             :     }
    3178             : 
    3179          92 :     return fetch;
    3180             : }
    3181             : 
    3182             : /*
    3183             :  * Process remainder of FETCH/MOVE direction after FORWARD or BACKWARD.
    3184             :  * Allows these cases:
    3185             :  *   FORWARD expr,  FORWARD ALL,  FORWARD
    3186             :  *   BACKWARD expr, BACKWARD ALL, BACKWARD
    3187             :  */
    3188             : static void
    3189          12 : complete_direction(PLpgSQL_stmt_fetch *fetch,  bool *check_FROM)
    3190             : {
    3191             :     int         tok;
    3192             : 
    3193          12 :     tok = yylex();
    3194          12 :     if (tok == 0)
    3195           0 :         yyerror("unexpected end of function definition");
    3196             : 
    3197          12 :     if (tok == K_FROM || tok == K_IN)
    3198             :     {
    3199           4 :         *check_FROM = false;
    3200           4 :         return;
    3201             :     }
    3202             : 
    3203           8 :     if (tok == K_ALL)
    3204             :     {
    3205           4 :         fetch->how_many = FETCH_ALL;
    3206           4 :         fetch->returns_multiple_rows = true;
    3207           4 :         *check_FROM = true;
    3208           4 :         return;
    3209             :     }
    3210             : 
    3211           4 :     plpgsql_push_back_token(tok);
    3212           4 :     fetch->expr = read_sql_expression2(K_FROM, K_IN,
    3213             :                                        "FROM or IN",
    3214             :                                        NULL);
    3215           4 :     fetch->returns_multiple_rows = true;
    3216           4 :     *check_FROM = false;
    3217             : }
    3218             : 
    3219             : 
    3220             : static PLpgSQL_stmt *
    3221        4858 : make_return_stmt(int location)
    3222             : {
    3223             :     PLpgSQL_stmt_return *new;
    3224             : 
    3225        4858 :     new = palloc0(sizeof(PLpgSQL_stmt_return));
    3226        4858 :     new->cmd_type = PLPGSQL_STMT_RETURN;
    3227        4858 :     new->lineno   = plpgsql_location_to_lineno(location);
    3228        4858 :     new->stmtid    = ++plpgsql_curr_compile->nstatements;
    3229        4858 :     new->expr      = NULL;
    3230        4858 :     new->retvarno = -1;
    3231             : 
    3232        4858 :     if (plpgsql_curr_compile->fn_retset)
    3233             :     {
    3234          24 :         if (yylex() != ';')
    3235           0 :             ereport(ERROR,
    3236             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    3237             :                      errmsg("RETURN cannot have a parameter in function returning set"),
    3238             :                      errhint("Use RETURN NEXT or RETURN QUERY."),
    3239             :                      parser_errposition(yylloc)));
    3240             :     }
    3241        4834 :     else if (plpgsql_curr_compile->fn_rettype == VOIDOID)
    3242             :     {
    3243          52 :         if (yylex() != ';')
    3244             :         {
    3245          10 :             if (plpgsql_curr_compile->fn_prokind == PROKIND_PROCEDURE)
    3246           2 :                 ereport(ERROR,
    3247             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    3248             :                          errmsg("RETURN cannot have a parameter in a procedure"),
    3249             :                          parser_errposition(yylloc)));
    3250             :             else
    3251           8 :                 ereport(ERROR,
    3252             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
    3253             :                          errmsg("RETURN cannot have a parameter in function returning void"),
    3254             :                          parser_errposition(yylloc)));
    3255             :         }
    3256             :     }
    3257        4782 :     else if (plpgsql_curr_compile->out_param_varno >= 0)
    3258             :     {
    3259          36 :         if (yylex() != ';')
    3260           4 :             ereport(ERROR,
    3261             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    3262             :                      errmsg("RETURN cannot have a parameter in function with OUT parameters"),
    3263             :                      parser_errposition(yylloc)));
    3264          32 :         new->retvarno = plpgsql_curr_compile->out_param_varno;
    3265             :     }
    3266             :     else
    3267             :     {
    3268             :         /*
    3269             :          * We want to special-case simple variable references for efficiency.
    3270             :          * So peek ahead to see if that's what we have.
    3271             :          */
    3272        4746 :         int     tok = yylex();
    3273             : 
    3274        4746 :         if (tok == T_DATUM && plpgsql_peek() == ';' &&
    3275        2778 :             (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_VAR ||
    3276        2036 :              yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_PROMISE ||
    3277        2036 :              yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
    3278        2036 :              yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC))
    3279             :         {
    3280        2736 :             new->retvarno = yylval.wdatum.datum->dno;
    3281             :             /* eat the semicolon token that we only peeked at above */
    3282        2736 :             tok = yylex();
    3283        2736 :             Assert(tok == ';');
    3284             :         }
    3285             :         else
    3286             :         {
    3287             :             /*
    3288             :              * Not (just) a variable name, so treat as expression.
    3289             :              *
    3290             :              * Note that a well-formed expression is _required_ here;
    3291             :              * anything else is a compile-time error.
    3292             :              */
    3293        2010 :             plpgsql_push_back_token(tok);
    3294        2010 :             new->expr = read_sql_expression(';', ";");
    3295             :         }
    3296             :     }
    3297             : 
    3298        4840 :     return (PLpgSQL_stmt *) new;
    3299             : }
    3300             : 
    3301             : 
    3302             : static PLpgSQL_stmt *
    3303         186 : make_return_next_stmt(int location)
    3304             : {
    3305             :     PLpgSQL_stmt_return_next *new;
    3306             : 
    3307         186 :     if (!plpgsql_curr_compile->fn_retset)
    3308           0 :         ereport(ERROR,
    3309             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3310             :                  errmsg("cannot use RETURN NEXT in a non-SETOF function"),
    3311             :                  parser_errposition(location)));
    3312             : 
    3313         186 :     new = palloc0(sizeof(PLpgSQL_stmt_return_next));
    3314         186 :     new->cmd_type    = PLPGSQL_STMT_RETURN_NEXT;
    3315         186 :     new->lineno      = plpgsql_location_to_lineno(location);
    3316         186 :     new->stmtid      = ++plpgsql_curr_compile->nstatements;
    3317         186 :     new->expr        = NULL;
    3318         186 :     new->retvarno    = -1;
    3319             : 
    3320         186 :     if (plpgsql_curr_compile->out_param_varno >= 0)
    3321             :     {
    3322          48 :         if (yylex() != ';')
    3323           0 :             ereport(ERROR,
    3324             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    3325             :                      errmsg("RETURN NEXT cannot have a parameter in function with OUT parameters"),
    3326             :                      parser_errposition(yylloc)));
    3327          48 :         new->retvarno = plpgsql_curr_compile->out_param_varno;
    3328             :     }
    3329             :     else
    3330             :     {
    3331             :         /*
    3332             :          * We want to special-case simple variable references for efficiency.
    3333             :          * So peek ahead to see if that's what we have.
    3334             :          */
    3335         138 :         int     tok = yylex();
    3336             : 
    3337         138 :         if (tok == T_DATUM && plpgsql_peek() == ';' &&
    3338         112 :             (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_VAR ||
    3339          48 :              yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_PROMISE ||
    3340          48 :              yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
    3341          48 :              yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC))
    3342             :         {
    3343         112 :             new->retvarno = yylval.wdatum.datum->dno;
    3344             :             /* eat the semicolon token that we only peeked at above */
    3345         112 :             tok = yylex();
    3346         112 :             Assert(tok == ';');
    3347             :         }
    3348             :         else
    3349             :         {
    3350             :             /*
    3351             :              * Not (just) a variable name, so treat as expression.
    3352             :              *
    3353             :              * Note that a well-formed expression is _required_ here;
    3354             :              * anything else is a compile-time error.
    3355             :              */
    3356          26 :             plpgsql_push_back_token(tok);
    3357          26 :             new->expr = read_sql_expression(';', ";");
    3358             :         }
    3359             :     }
    3360             : 
    3361         186 :     return (PLpgSQL_stmt *) new;
    3362             : }
    3363             : 
    3364             : 
    3365             : static PLpgSQL_stmt *
    3366          96 : make_return_query_stmt(int location)
    3367             : {
    3368             :     PLpgSQL_stmt_return_query *new;
    3369             :     int         tok;
    3370             : 
    3371          96 :     if (!plpgsql_curr_compile->fn_retset)
    3372           0 :         ereport(ERROR,
    3373             :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
    3374             :                  errmsg("cannot use RETURN QUERY in a non-SETOF function"),
    3375             :                  parser_errposition(location)));
    3376             : 
    3377          96 :     new = palloc0(sizeof(PLpgSQL_stmt_return_query));
    3378          96 :     new->cmd_type = PLPGSQL_STMT_RETURN_QUERY;
    3379          96 :     new->lineno = plpgsql_location_to_lineno(location);
    3380          96 :     new->stmtid = ++plpgsql_curr_compile->nstatements;
    3381             : 
    3382             :     /* check for RETURN QUERY EXECUTE */
    3383          96 :     if ((tok = yylex()) != K_EXECUTE)
    3384             :     {
    3385             :         /* ordinary static query */
    3386          44 :         plpgsql_push_back_token(tok);
    3387          44 :         new->query = read_sql_stmt();
    3388             :     }
    3389             :     else
    3390             :     {
    3391             :         /* dynamic SQL */
    3392             :         int     term;
    3393             : 
    3394          52 :         new->dynquery = read_sql_expression2(';', K_USING, "; or USING",
    3395             :                                              &term);
    3396          52 :         if (term == K_USING)
    3397             :         {
    3398             :             do
    3399             :             {
    3400             :                 PLpgSQL_expr *expr;
    3401             : 
    3402           8 :                 expr = read_sql_expression2(',', ';', ", or ;", &term);
    3403           8 :                 new->params = lappend(new->params, expr);
    3404           8 :             } while (term == ',');
    3405             :         }
    3406             :     }
    3407             : 
    3408          96 :     return (PLpgSQL_stmt *) new;
    3409             : }
    3410             : 
    3411             : 
    3412             : /* convenience routine to fetch the name of a T_DATUM */
    3413             : static char *
    3414        1264 : NameOfDatum(PLwdatum *wdatum)
    3415             : {
    3416        1264 :     if (wdatum->ident)
    3417        1232 :         return wdatum->ident;
    3418             :     Assert(wdatum->idents != NIL);
    3419          32 :     return NameListToString(wdatum->idents);
    3420             : }
    3421             : 
    3422             : static void
    3423        8476 : check_assignable(PLpgSQL_datum *datum, int location)
    3424             : {
    3425        8476 :     switch (datum->dtype)
    3426             :     {
    3427        7998 :         case PLPGSQL_DTYPE_VAR:
    3428             :         case PLPGSQL_DTYPE_PROMISE:
    3429             :         case PLPGSQL_DTYPE_REC:
    3430        7998 :             if (((PLpgSQL_variable *) datum)->isconst)
    3431          10 :                 ereport(ERROR,
    3432             :                         (errcode(ERRCODE_ERROR_IN_ASSIGNMENT),
    3433             :                          errmsg("variable \"%s\" is declared CONSTANT",
    3434             :                                 ((PLpgSQL_variable *) datum)->refname),
    3435             :                          parser_errposition(location)));
    3436        7988 :             break;
    3437          12 :         case PLPGSQL_DTYPE_ROW:
    3438             :             /* always assignable; member vars were checked at compile time */
    3439          12 :             break;
    3440         466 :         case PLPGSQL_DTYPE_RECFIELD:
    3441             :             /* assignable if parent record is */
    3442         466 :             check_assignable(plpgsql_Datums[((PLpgSQL_recfield *) datum)->recparentno],
    3443             :                              location);
    3444         462 :             break;
    3445           0 :         default:
    3446           0 :             elog(ERROR, "unrecognized dtype: %d", datum->dtype);
    3447             :             break;
    3448             :     }
    3449        8462 : }
    3450             : 
    3451             : /*
    3452             :  * Read the argument of an INTO clause.  On entry, we have just read the
    3453             :  * INTO keyword.
    3454             :  */
    3455             : static void
    3456        1066 : read_into_target(PLpgSQL_variable **target, bool *strict)
    3457             : {
    3458             :     int         tok;
    3459             : 
    3460             :     /* Set default results */
    3461        1066 :     *target = NULL;
    3462        1066 :     if (strict)
    3463         986 :         *strict = false;
    3464             : 
    3465        1066 :     tok = yylex();
    3466        1066 :     if (strict && tok == K_STRICT)
    3467             :     {
    3468          88 :         *strict = true;
    3469          88 :         tok = yylex();
    3470             :     }
    3471             : 
    3472             :     /*
    3473             :      * Currently, a row or record variable can be the single INTO target,
    3474             :      * but not a member of a multi-target list.  So we throw error if there
    3475             :      * is a comma after it, because that probably means the user tried to
    3476             :      * write a multi-target list.  If this ever gets generalized, we should
    3477             :      * probably refactor read_into_scalar_list so it handles all cases.
    3478             :      */
    3479        1066 :     switch (tok)
    3480             :     {
    3481        1066 :         case T_DATUM:
    3482        1066 :             if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
    3483        1066 :                 yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC)
    3484             :             {
    3485         396 :                 check_assignable(yylval.wdatum.datum, yylloc);
    3486         396 :                 *target = (PLpgSQL_variable *) yylval.wdatum.datum;
    3487             : 
    3488         396 :                 if ((tok = yylex()) == ',')
    3489           0 :                     ereport(ERROR,
    3490             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    3491             :                              errmsg("record variable cannot be part of multiple-item INTO list"),
    3492             :                              parser_errposition(yylloc)));
    3493         396 :                 plpgsql_push_back_token(tok);
    3494             :             }
    3495             :             else
    3496             :             {
    3497         670 :                 *target = (PLpgSQL_variable *)
    3498         670 :                     read_into_scalar_list(NameOfDatum(&(yylval.wdatum)),
    3499             :                                           yylval.wdatum.datum, yylloc);
    3500             :             }
    3501        1066 :             break;
    3502             : 
    3503           0 :         default:
    3504             :             /* just to give a better message than "syntax error" */
    3505           0 :             current_token_is_not_variable(tok);
    3506             :     }
    3507        1066 : }
    3508             : 
    3509             : /*
    3510             :  * Given the first datum and name in the INTO list, continue to read
    3511             :  * comma-separated scalar variables until we run out. Then construct
    3512             :  * and return a fake "row" variable that represents the list of
    3513             :  * scalars.
    3514             :  */
    3515             : static PLpgSQL_row *
    3516         686 : read_into_scalar_list(char *initial_name,
    3517             :                       PLpgSQL_datum *initial_datum,
    3518             :                       int initial_location)
    3519             : {
    3520             :     int              nfields;
    3521             :     char            *fieldnames[1024];
    3522             :     int              varnos[1024];
    3523             :     PLpgSQL_row     *row;
    3524             :     int              tok;
    3525             : 
    3526         686 :     check_assignable(initial_datum, initial_location);
    3527         682 :     fieldnames[0] = initial_name;
    3528         682 :     varnos[0]     = initial_datum->dno;
    3529         682 :     nfields       = 1;
    3530             : 
    3531         778 :     while ((tok = yylex()) == ',')
    3532             :     {
    3533             :         /* Check for array overflow */
    3534          96 :         if (nfields >= 1024)
    3535           0 :             ereport(ERROR,
    3536             :                     (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    3537             :                      errmsg("too many INTO variables specified"),
    3538             :                      parser_errposition(yylloc)));
    3539             : 
    3540          96 :         tok = yylex();
    3541          96 :         switch (tok)
    3542             :         {
    3543          96 :             case T_DATUM:
    3544          96 :                 check_assignable(yylval.wdatum.datum, yylloc);
    3545          96 :                 if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
    3546          96 :                     yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC)
    3547           0 :                     ereport(ERROR,
    3548             :                             (errcode(ERRCODE_SYNTAX_ERROR),
    3549             :                              errmsg("\"%s\" is not a scalar variable",
    3550             :                                     NameOfDatum(&(yylval.wdatum))),
    3551             :                              parser_errposition(yylloc)));
    3552          96 :                 fieldnames[nfields] = NameOfDatum(&(yylval.wdatum));
    3553          96 :                 varnos[nfields++]   = yylval.wdatum.datum->dno;
    3554          96 :                 break;
    3555             : 
    3556           0 :             default:
    3557             :                 /* just to give a better message than "syntax error" */
    3558           0 :                 current_token_is_not_variable(tok);
    3559             :         }
    3560             :     }
    3561             : 
    3562             :     /*
    3563             :      * We read an extra, non-comma token from yylex(), so push it
    3564             :      * back onto the input stream
    3565             :      */
    3566         682 :     plpgsql_push_back_token(tok);
    3567             : 
    3568         682 :     row = palloc0(sizeof(PLpgSQL_row));
    3569         682 :     row->dtype = PLPGSQL_DTYPE_ROW;
    3570         682 :     row->refname = "(unnamed row)";
    3571         682 :     row->lineno = plpgsql_location_to_lineno(initial_location);
    3572         682 :     row->rowtupdesc = NULL;
    3573         682 :     row->nfields = nfields;
    3574         682 :     row->fieldnames = palloc(sizeof(char *) * nfields);
    3575         682 :     row->varnos = palloc(sizeof(int) * nfields);
    3576        1460 :     while (--nfields >= 0)
    3577             :     {
    3578         778 :         row->fieldnames[nfields] = fieldnames[nfields];
    3579         778 :         row->varnos[nfields] = varnos[nfields];
    3580             :     }
    3581             : 
    3582         682 :     plpgsql_adddatum((PLpgSQL_datum *)row);
    3583             : 
    3584         682 :     return row;
    3585             : }
    3586             : 
    3587             : /*
    3588             :  * Convert a single scalar into a "row" list.  This is exactly
    3589             :  * like read_into_scalar_list except we never consume any input.
    3590             :  *
    3591             :  * Note: lineno could be computed from location, but since callers
    3592             :  * have it at hand already, we may as well pass it in.
    3593             :  */
    3594             : static PLpgSQL_row *
    3595         190 : make_scalar_list1(char *initial_name,
    3596             :                   PLpgSQL_datum *initial_datum,
    3597             :                   int lineno, int location)
    3598             : {
    3599             :     PLpgSQL_row     *row;
    3600             : 
    3601         190 :     check_assignable(initial_datum, location);
    3602             : 
    3603         190 :     row = palloc0(sizeof(PLpgSQL_row));
    3604         190 :     row->dtype = PLPGSQL_DTYPE_ROW;
    3605         190 :     row->refname = "(unnamed row)";
    3606         190 :     row->lineno = lineno;
    3607         190 :     row->rowtupdesc = NULL;
    3608         190 :     row->nfields = 1;
    3609         190 :     row->fieldnames = palloc(sizeof(char *));
    3610         190 :     row->varnos = palloc(sizeof(int));
    3611         190 :     row->fieldnames[0] = initial_name;
    3612         190 :     row->varnos[0] = initial_datum->dno;
    3613             : 
    3614         190 :     plpgsql_adddatum((PLpgSQL_datum *)row);
    3615             : 
    3616         190 :     return row;
    3617             : }
    3618             : 
    3619             : /*
    3620             :  * When the PL/pgSQL parser expects to see a SQL statement, it is very
    3621             :  * liberal in what it accepts; for example, we often assume an
    3622             :  * unrecognized keyword is the beginning of a SQL statement. This
    3623             :  * avoids the need to duplicate parts of the SQL grammar in the
    3624             :  * PL/pgSQL grammar, but it means we can accept wildly malformed
    3625             :  * input. To try and catch some of the more obviously invalid input,
    3626             :  * we run the strings we expect to be SQL statements through the main
    3627             :  * SQL parser.
    3628             :  *
    3629             :  * We only invoke the raw parser (not the analyzer); this doesn't do
    3630             :  * any database access and does not check any semantic rules, it just
    3631             :  * checks for basic syntactic correctness. We do this here, rather
    3632             :  * than after parsing has finished, because a malformed SQL statement
    3633             :  * may cause the PL/pgSQL parser to become confused about statement
    3634             :  * borders. So it is best to bail out as early as we can.
    3635             :  *
    3636             :  * It is assumed that "stmt" represents a copy of the function source text
    3637             :  * beginning at offset "location".  We use this assumption to transpose
    3638             :  * any error cursor position back to the function source text.
    3639             :  * If no error cursor is provided, we'll just point at "location".
    3640             :  */
    3641             : static void
    3642       27926 : check_sql_expr(const char *stmt, RawParseMode parseMode, int location)
    3643             : {
    3644             :     sql_error_callback_arg cbarg;
    3645             :     ErrorContextCallback  syntax_errcontext;
    3646             :     MemoryContext oldCxt;
    3647             : 
    3648       27926 :     if (!plpgsql_check_syntax)
    3649       15614 :         return;
    3650             : 
    3651       12312 :     cbarg.location = location;
    3652             : 
    3653       12312 :     syntax_errcontext.callback = plpgsql_sql_error_callback;
    3654       12312 :     syntax_errcontext.arg = &cbarg;
    3655       12312 :     syntax_errcontext.previous = error_context_stack;
    3656       12312 :     error_context_stack = &syntax_errcontext;
    3657             : 
    3658       12312 :     oldCxt = MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
    3659       12312 :     (void) raw_parser(stmt, parseMode);
    3660       12304 :     MemoryContextSwitchTo(oldCxt);
    3661             : 
    3662             :     /* Restore former ereport callback */
    3663       12304 :     error_context_stack = syntax_errcontext.previous;
    3664             : }
    3665             : 
    3666             : static void
    3667          14 : plpgsql_sql_error_callback(void *arg)
    3668             : {
    3669          14 :     sql_error_callback_arg *cbarg = (sql_error_callback_arg *) arg;
    3670             :     int         errpos;
    3671             : 
    3672             :     /*
    3673             :      * First, set up internalerrposition to point to the start of the
    3674             :      * statement text within the function text.  Note this converts
    3675             :      * location (a byte offset) to a character number.
    3676             :      */
    3677          14 :     parser_errposition(cbarg->location);
    3678             : 
    3679             :     /*
    3680             :      * If the core parser provided an error position, transpose it.
    3681             :      * Note we are dealing with 1-based character numbers at this point.
    3682             :      */
    3683          14 :     errpos = geterrposition();
    3684          14 :     if (errpos > 0)
    3685             :     {
    3686          12 :         int     myerrpos = getinternalerrposition();
    3687             : 
    3688          12 :         if (myerrpos > 0)        /* safety check */
    3689          12 :             internalerrposition(myerrpos + errpos - 1);
    3690             :     }
    3691             : 
    3692             :     /* In any case, flush errposition --- we want internalerrposition only */
    3693          14 :     errposition(0);
    3694          14 : }
    3695             : 
    3696             : /*
    3697             :  * Parse a SQL datatype name and produce a PLpgSQL_type structure.
    3698             :  *
    3699             :  * The heavy lifting is done elsewhere.  Here we are only concerned
    3700             :  * with setting up an errcontext link that will let us give an error
    3701             :  * cursor pointing into the plpgsql function source, if necessary.
    3702             :  * This is handled the same as in check_sql_expr(), and we likewise
    3703             :  * expect that the given string is a copy from the source text.
    3704             :  */
    3705             : static PLpgSQL_type *
    3706        4056 : parse_datatype(const char *string, int location)
    3707             : {
    3708             :     TypeName   *typeName;
    3709             :     Oid         type_id;
    3710             :     int32       typmod;
    3711             :     sql_error_callback_arg cbarg;
    3712             :     ErrorContextCallback  syntax_errcontext;
    3713             : 
    3714        4056 :     cbarg.location = location;
    3715             : 
    3716        4056 :     syntax_errcontext.callback = plpgsql_sql_error_callback;
    3717        4056 :     syntax_errcontext.arg = &cbarg;
    3718        4056 :     syntax_errcontext.previous = error_context_stack;
    3719        4056 :     error_context_stack = &syntax_errcontext;
    3720             : 
    3721             :     /* Let the main parser try to parse it under standard SQL rules */
    3722        4056 :     typeName = typeStringToTypeName(string);
    3723        4056 :     typenameTypeIdAndMod(NULL, typeName, &type_id, &typmod);
    3724             : 
    3725             :     /* Restore former ereport callback */
    3726        4054 :     error_context_stack = syntax_errcontext.previous;
    3727             : 
    3728             :     /* Okay, build a PLpgSQL_type data structure for it */
    3729        8108 :     return plpgsql_build_datatype(type_id, typmod,
    3730        4054 :                                   plpgsql_curr_compile->fn_input_collation,
    3731             :                                   typeName);
    3732             : }
    3733             : 
    3734             : /*
    3735             :  * Check block starting and ending labels match.
    3736             :  */
    3737             : static void
    3738        5976 : check_labels(const char *start_label, const char *end_label, int end_location)
    3739             : {
    3740        5976 :     if (end_label)
    3741             :     {
    3742          10 :         if (!start_label)
    3743           4 :             ereport(ERROR,
    3744             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    3745             :                      errmsg("end label \"%s\" specified for unlabeled block",
    3746             :                             end_label),
    3747             :                      parser_errposition(end_location)));
    3748             : 
    3749           6 :         if (strcmp(start_label, end_label) != 0)
    3750           2 :             ereport(ERROR,
    3751             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    3752             :                      errmsg("end label \"%s\" differs from block's label \"%s\"",
    3753             :                             end_label, start_label),
    3754             :                      parser_errposition(end_location)));
    3755             :     }
    3756        5970 : }
    3757             : 
    3758             : /*
    3759             :  * Read the arguments (if any) for a cursor, followed by the until token
    3760             :  *
    3761             :  * If cursor has no args, just swallow the until token and return NULL.
    3762             :  * If it does have args, we expect to see "( arg [, arg ...] )" followed
    3763             :  * by the until token, where arg may be a plain expression, or a named
    3764             :  * parameter assignment of the form argname := expr. Consume all that and
    3765             :  * return a SELECT query that evaluates the expression(s) (without the outer
    3766             :  * parens).
    3767             :  */
    3768             : static PLpgSQL_expr *
    3769          82 : read_cursor_args(PLpgSQL_var *cursor, int until)
    3770             : {
    3771             :     PLpgSQL_expr *expr;
    3772             :     PLpgSQL_row *row;
    3773             :     int         tok;
    3774             :     int         argc;
    3775             :     char      **argv;
    3776             :     StringInfoData ds;
    3777          82 :     bool        any_named = false;
    3778             : 
    3779          82 :     tok = yylex();
    3780          82 :     if (cursor->cursor_explicit_argrow < 0)
    3781             :     {
    3782             :         /* No arguments expected */
    3783          34 :         if (tok == '(')
    3784           0 :             ereport(ERROR,
    3785             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    3786             :                      errmsg("cursor \"%s\" has no arguments",
    3787             :                             cursor->refname),
    3788             :                      parser_errposition(yylloc)));
    3789             : 
    3790          34 :         if (tok != until)
    3791           0 :             yyerror("syntax error");
    3792             : 
    3793          34 :         return NULL;
    3794             :     }
    3795             : 
    3796             :     /* Else better provide arguments */
    3797          48 :     if (tok != '(')
    3798           0 :         ereport(ERROR,
    3799             :                 (errcode(ERRCODE_SYNTAX_ERROR),
    3800             :                  errmsg("cursor \"%s\" has arguments",
    3801             :                         cursor->refname),
    3802             :                  parser_errposition(yylloc)));
    3803             : 
    3804             :     /*
    3805             :      * Read the arguments, one by one.
    3806             :      */
    3807          48 :     row = (PLpgSQL_row *) plpgsql_Datums[cursor->cursor_explicit_argrow];
    3808          48 :     argv = (char **) palloc0(row->nfields * sizeof(char *));
    3809             : 
    3810         128 :     for (argc = 0; argc < row->nfields; argc++)
    3811             :     {
    3812             :         PLpgSQL_expr *item;
    3813             :         int     endtoken;
    3814             :         int     argpos;
    3815             :         int     tok1,
    3816             :                 tok2;
    3817             :         int     arglocation;
    3818             : 
    3819             :         /* Check if it's a named parameter: "param := value" */
    3820          96 :         plpgsql_peek2(&tok1, &tok2, &arglocation, NULL);
    3821          96 :         if (tok1 == IDENT && tok2 == COLON_EQUALS)
    3822          52 :         {
    3823             :             char   *argname;
    3824             :             IdentifierLookup save_IdentifierLookup;
    3825             : 
    3826             :             /* Read the argument name, ignoring any matching variable */
    3827          52 :             save_IdentifierLookup = plpgsql_IdentifierLookup;
    3828          52 :             plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_DECLARE;
    3829          52 :             yylex();
    3830          52 :             argname = yylval.str;
    3831          52 :             plpgsql_IdentifierLookup = save_IdentifierLookup;
    3832             : 
    3833             :             /* Match argument name to cursor arguments */
    3834          88 :             for (argpos = 0; argpos < row->nfields; argpos++)
    3835             :             {
    3836          88 :                 if (strcmp(row->fieldnames[argpos], argname) == 0)
    3837          52 :                     break;
    3838             :             }
    3839          52 :             if (argpos == row->nfields)
    3840           0 :                 ereport(ERROR,
    3841             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    3842             :                          errmsg("cursor \"%s\" has no argument named \"%s\"",
    3843             :                                 cursor->refname, argname),
    3844             :                          parser_errposition(yylloc)));
    3845             : 
    3846             :             /*
    3847             :              * Eat the ":=". We already peeked, so the error should never
    3848             :              * happen.
    3849             :              */
    3850          52 :             tok2 = yylex();
    3851          52 :             if (tok2 != COLON_EQUALS)
    3852           0 :                 yyerror("syntax error");
    3853             : 
    3854          52 :             any_named = true;
    3855             :         }
    3856             :         else
    3857          44 :             argpos = argc;
    3858             : 
    3859          96 :         if (argv[argpos] != NULL)
    3860          12 :             ereport(ERROR,
    3861             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    3862             :                      errmsg("value for parameter \"%s\" of cursor \"%s\" specified more than once",
    3863             :                             row->fieldnames[argpos], cursor->refname),
    3864             :                      parser_errposition(arglocation)));
    3865             : 
    3866             :         /*
    3867             :          * Read the value expression. To provide the user with meaningful
    3868             :          * parse error positions, we check the syntax immediately, instead of
    3869             :          * checking the final expression that may have the arguments
    3870             :          * reordered. Trailing whitespace must not be trimmed, because
    3871             :          * otherwise input of the form (param -- comment\n, param) would be
    3872             :          * translated into a form where the second parameter is commented
    3873             :          * out.
    3874             :          */
    3875          84 :         item = read_sql_construct(',', ')', 0,
    3876             :                                   ",\" or \")",
    3877             :                                   RAW_PARSE_PLPGSQL_EXPR,
    3878             :                                   true, true,
    3879             :                                   false, /* do not trim */
    3880             :                                   NULL, &endtoken);
    3881             : 
    3882          84 :         argv[argpos] = item->query;
    3883             : 
    3884          84 :         if (endtoken == ')' && !(argc == row->nfields - 1))
    3885           4 :             ereport(ERROR,
    3886             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    3887             :                      errmsg("not enough arguments for cursor \"%s\"",
    3888             :                             cursor->refname),
    3889             :                      parser_errposition(yylloc)));
    3890             : 
    3891          80 :         if (endtoken == ',' && (argc == row->nfields - 1))
    3892           0 :             ereport(ERROR,
    3893             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    3894             :                      errmsg("too many arguments for cursor \"%s\"",
    3895             :                             cursor->refname),
    3896             :                      parser_errposition(yylloc)));
    3897             :     }
    3898             : 
    3899             :     /* Make positional argument list */
    3900          32 :     initStringInfo(&ds);
    3901         100 :     for (argc = 0; argc < row->nfields; argc++)
    3902             :     {
    3903             :         Assert(argv[argc] != NULL);
    3904             : 
    3905             :         /*
    3906             :          * Because named notation allows permutated argument lists, include
    3907             :          * the parameter name for meaningful runtime errors.
    3908             :          */
    3909          68 :         appendStringInfoString(&ds, argv[argc]);
    3910          68 :         if (any_named)
    3911          36 :             appendStringInfo(&ds, " AS %s",
    3912          36 :                              quote_identifier(row->fieldnames[argc]));
    3913          68 :         if (argc < row->nfields - 1)
    3914          36 :             appendStringInfoString(&ds, ", ");
    3915             :     }
    3916             : 
    3917          32 :     expr = palloc0(sizeof(PLpgSQL_expr));
    3918          32 :     expr->query          = pstrdup(ds.data);
    3919          32 :     expr->parseMode      = RAW_PARSE_PLPGSQL_EXPR;
    3920          32 :     expr->plan           = NULL;
    3921          32 :     expr->paramnos       = NULL;
    3922          32 :     expr->target_param   = -1;
    3923          32 :     expr->ns            = plpgsql_ns_top();
    3924          32 :     pfree(ds.data);
    3925             : 
    3926             :     /* Next we'd better find the until token */
    3927          32 :     tok = yylex();
    3928          32 :     if (tok != until)
    3929           0 :         yyerror("syntax error");
    3930             : 
    3931          32 :     return expr;
    3932             : }
    3933             : 
    3934             : /*
    3935             :  * Parse RAISE ... USING options
    3936             :  */
    3937             : static List *
    3938         148 : read_raise_options(void)
    3939             : {
    3940         148 :     List       *result = NIL;
    3941             : 
    3942             :     for (;;)
    3943          68 :     {
    3944             :         PLpgSQL_raise_option *opt;
    3945             :         int     tok;
    3946             : 
    3947         216 :         if ((tok = yylex()) == 0)
    3948           0 :             yyerror("unexpected end of function definition");
    3949             : 
    3950         216 :         opt = (PLpgSQL_raise_option *) palloc(sizeof(PLpgSQL_raise_option));
    3951             : 
    3952         216 :         if (tok_is_keyword(tok, &yylval,
    3953             :                            K_ERRCODE, "errcode"))
    3954          32 :             opt->opt_type = PLPGSQL_RAISEOPTION_ERRCODE;
    3955         184 :         else if (tok_is_keyword(tok, &yylval,
    3956             :                                 K_MESSAGE, "message"))
    3957         112 :             opt->opt_type = PLPGSQL_RAISEOPTION_MESSAGE;
    3958          72 :         else if (tok_is_keyword(tok, &yylval,
    3959             :                                 K_DETAIL, "detail"))
    3960          32 :             opt->opt_type = PLPGSQL_RAISEOPTION_DETAIL;
    3961          40 :         else if (tok_is_keyword(tok, &yylval,
    3962             :                                 K_HINT, "hint"))
    3963          10 :             opt->opt_type = PLPGSQL_RAISEOPTION_HINT;
    3964          30 :         else if (tok_is_keyword(tok, &yylval,
    3965             :                                 K_COLUMN, "column"))
    3966           6 :             opt->opt_type = PLPGSQL_RAISEOPTION_COLUMN;
    3967          24 :         else if (tok_is_keyword(tok, &yylval,
    3968             :                                 K_CONSTRAINT, "constraint"))
    3969           6 :             opt->opt_type = PLPGSQL_RAISEOPTION_CONSTRAINT;
    3970          18 :         else if (tok_is_keyword(tok, &yylval,
    3971             :                                 K_DATATYPE, "datatype"))
    3972           6 :             opt->opt_type = PLPGSQL_RAISEOPTION_DATATYPE;
    3973          12 :         else if (tok_is_keyword(tok, &yylval,
    3974             :                                 K_TABLE, "table"))
    3975           6 :             opt->opt_type = PLPGSQL_RAISEOPTION_TABLE;
    3976           6 :         else if (tok_is_keyword(tok, &yylval,
    3977             :                                 K_SCHEMA, "schema"))
    3978           6 :             opt->opt_type = PLPGSQL_RAISEOPTION_SCHEMA;
    3979             :         else
    3980           0 :             yyerror("unrecognized RAISE statement option");
    3981             : 
    3982         216 :         tok = yylex();
    3983         216 :         if (tok != '=' && tok != COLON_EQUALS)
    3984           0 :             yyerror("syntax error, expected \"=\"");
    3985             : 
    3986         216 :         opt->expr = read_sql_expression2(',', ';', ", or ;", &tok);
    3987             : 
    3988         216 :         result = lappend(result, opt);
    3989             : 
    3990         216 :         if (tok == ';')
    3991         148 :             break;
    3992             :     }
    3993             : 
    3994         148 :     return result;
    3995             : }
    3996             : 
    3997             : /*
    3998             :  * Check that the number of parameter placeholders in the message matches the
    3999             :  * number of parameters passed to it, if a message was given.
    4000             :  */
    4001             : static void
    4002        3952 : check_raise_parameters(PLpgSQL_stmt_raise *stmt)
    4003             : {
    4004             :     char       *cp;
    4005        3952 :     int         expected_nparams = 0;
    4006             : 
    4007        3952 :     if (stmt->message == NULL)
    4008         168 :         return;
    4009             : 
    4010       88292 :     for (cp = stmt->message; *cp; cp++)
    4011             :     {
    4012       84508 :         if (cp[0] == '%')
    4013             :         {
    4014             :             /* ignore literal % characters */
    4015        9776 :             if (cp[1] == '%')
    4016           4 :                 cp++;
    4017             :             else
    4018        9772 :                 expected_nparams++;
    4019             :         }
    4020             :     }
    4021             : 
    4022        3784 :     if (expected_nparams < list_length(stmt->params))
    4023           4 :         ereport(ERROR,
    4024             :                 (errcode(ERRCODE_SYNTAX_ERROR),
    4025             :                 errmsg("too many parameters specified for RAISE")));
    4026        3780 :     if (expected_nparams > list_length(stmt->params))
    4027           4 :         ereport(ERROR,
    4028             :                 (errcode(ERRCODE_SYNTAX_ERROR),
    4029             :                 errmsg("too few parameters specified for RAISE")));
    4030             : }
    4031             : 
    4032             : /*
    4033             :  * Fix up CASE statement
    4034             :  */
    4035             : static PLpgSQL_stmt *
    4036          12 : make_case(int location, PLpgSQL_expr *t_expr,
    4037             :           List *case_when_list, List *else_stmts)
    4038             : {
    4039             :     PLpgSQL_stmt_case   *new;
    4040             : 
    4041          12 :     new = palloc(sizeof(PLpgSQL_stmt_case));
    4042          12 :     new->cmd_type = PLPGSQL_STMT_CASE;
    4043          12 :     new->lineno = plpgsql_location_to_lineno(location);
    4044          12 :     new->stmtid = ++plpgsql_curr_compile->nstatements;
    4045          12 :     new->t_expr = t_expr;
    4046          12 :     new->t_varno = 0;
    4047          12 :     new->case_when_list = case_when_list;
    4048          12 :     new->have_else = (else_stmts != NIL);
    4049             :     /* Get rid of list-with-NULL hack */
    4050          12 :     if (list_length(else_stmts) == 1 && linitial(else_stmts) == NULL)
    4051           0 :         new->else_stmts = NIL;
    4052             :     else
    4053          12 :         new->else_stmts = else_stmts;
    4054             : 
    4055             :     /*
    4056             :      * When test expression is present, we create a var for it and then
    4057             :      * convert all the WHEN expressions to "VAR IN (original_expression)".
    4058             :      * This is a bit klugy, but okay since we haven't yet done more than
    4059             :      * read the expressions as text.  (Note that previous parsing won't
    4060             :      * have complained if the WHEN ... THEN expression contained multiple
    4061             :      * comma-separated values.)
    4062             :      */
    4063          12 :     if (t_expr)
    4064             :     {
    4065             :         char    varname[32];
    4066             :         PLpgSQL_var *t_var;
    4067             :         ListCell *l;
    4068             : 
    4069             :         /* use a name unlikely to collide with any user names */
    4070          10 :         snprintf(varname, sizeof(varname), "__Case__Variable_%d__",
    4071             :                  plpgsql_nDatums);
    4072             : 
    4073             :         /*
    4074             :          * We don't yet know the result datatype of t_expr.  Build the
    4075             :          * variable as if it were INT4; we'll fix this at runtime if needed.
    4076             :          */
    4077             :         t_var = (PLpgSQL_var *)
    4078          10 :             plpgsql_build_variable(varname, new->lineno,
    4079             :                                    plpgsql_build_datatype(INT4OID,
    4080             :                                                           -1,
    4081             :                                                           InvalidOid,
    4082             :                                                           NULL),
    4083             :                                    true);
    4084          10 :         new->t_varno = t_var->dno;
    4085             : 
    4086          36 :         foreach(l, case_when_list)
    4087             :         {
    4088          26 :             PLpgSQL_case_when *cwt = (PLpgSQL_case_when *) lfirst(l);
    4089          26 :             PLpgSQL_expr *expr = cwt->expr;
    4090             :             StringInfoData  ds;
    4091             : 
    4092             :             /* We expect to have expressions not statements */
    4093             :             Assert(expr->parseMode == RAW_PARSE_PLPGSQL_EXPR);
    4094             : 
    4095             :             /* Do the string hacking */
    4096          26 :             initStringInfo(&ds);
    4097             : 
    4098          26 :             appendStringInfo(&ds, "\"%s\" IN (%s)",
    4099             :                              varname, expr->query);
    4100             : 
    4101          26 :             pfree(expr->query);
    4102          26 :             expr->query = pstrdup(ds.data);
    4103             :             /* Adjust expr's namespace to include the case variable */
    4104          26 :             expr->ns = plpgsql_ns_top();
    4105             : 
    4106          26 :             pfree(ds.data);
    4107             :         }
    4108             :     }
    4109             : 
    4110          12 :     return (PLpgSQL_stmt *) new;
    4111             : }

Generated by: LCOV version 1.13