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

Generated by: LCOV version 2.0-1