LCOV - code coverage report
Current view: top level - src/pl/plpgsql/src - pl_gram.y (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 1257 1403 89.6 %
Date: 2026-02-08 01:17:04 Functions: 28 30 93.3 %
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        9580 :                         *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          12 :                         if (strcmp($3, "on") == 0)
     392           6 :                             plpgsql_curr_compile->print_strict_params = true;
     393           6 :                         else if (strcmp($3, "off") == 0)
     394           6 :                             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           6 :                         plpgsql_curr_compile->resolve_option = PLPGSQL_RESOLVE_VARIABLE;
     405             :                     }
     406             :                 | '#' K_VARIABLE_CONFLICT K_USE_COLUMN
     407             :                     {
     408           6 :                         plpgsql_curr_compile->resolve_option = PLPGSQL_RESOLVE_COLUMN;
     409             :                     }
     410             :                 ;
     411             : 
     412             : option_value : T_WORD
     413             :                 {
     414          12 :                     $$ = $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        9808 :                         new = palloc0_object(PLpgSQL_stmt_block);
     430             : 
     431        9808 :                         new->cmd_type    = PLPGSQL_STMT_BLOCK;
     432        9808 :                         new->lineno      = plpgsql_location_to_lineno(@2, yyscanner);
     433        9808 :                         new->stmtid      = ++plpgsql_curr_compile->nstatements;
     434        9808 :                         new->label       = $1.label;
     435        9808 :                         new->n_initvars = $1.n_initvars;
     436        9808 :                         new->initvarnos = $1.initvarnos;
     437        9808 :                         new->body        = $3;
     438        9808 :                         new->exceptions  = $4;
     439             : 
     440        9808 :                         check_labels($1.label, $6, @6, yyscanner);
     441        9808 :                         plpgsql_ns_pop();
     442             : 
     443        9808 :                         $$ = (PLpgSQL_stmt *) new;
     444             :                     }
     445             :                 ;
     446             : 
     447             : 
     448             : decl_sect       : opt_block_label
     449             :                     {
     450             :                         /* done with decls, so resume identifier lookup */
     451        6284 :                         plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
     452        6284 :                         $$.label      = $1;
     453        6284 :                         $$.n_initvars = 0;
     454        6284 :                         $$.initvarnos = NULL;
     455             :                     }
     456             :                 | opt_block_label decl_start
     457             :                     {
     458          10 :                         plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
     459          10 :                         $$.label      = $1;
     460          10 :                         $$.n_initvars = 0;
     461          10 :                         $$.initvarnos = NULL;
     462             :                     }
     463             :                 | opt_block_label decl_start decl_stmts
     464             :                     {
     465        3642 :                         plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
     466        3642 :                         $$.label      = $1;
     467             :                         /* Remember variables declared in decl_stmts */
     468        3642 :                         $$.n_initvars = plpgsql_add_initdatums(&($$.initvarnos));
     469             :                     }
     470             :                 ;
     471             : 
     472             : decl_start      : K_DECLARE
     473             :                     {
     474             :                         /* Forget any variables created before block */
     475        3694 :                         plpgsql_add_initdatums(NULL);
     476             :                         /*
     477             :                          * Disable scanner lookup of identifiers while
     478             :                          * we process the decl_stmts
     479             :                          */
     480        3694 :                         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        5922 :                         if (OidIsValid($4))
     517             :                         {
     518          24 :                             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          24 :                             $3->collation = $4;
     525             :                         }
     526             : 
     527        5922 :                         var = plpgsql_build_variable($1.name, $1.lineno,
     528        5922 :                                                      $3, true);
     529        5918 :                         var->isconst = $2;
     530        5918 :                         var->notnull = $5;
     531        5918 :                         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        5918 :                         if (var->notnull && var->default_val == NULL)
     538           6 :                             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        5912 :                         if (var->default_val != NULL)
     545         812 :                             mark_expr_as_assignment_source(var->default_val,
     546             :                                                            (PLpgSQL_datum *) var);
     547             :                     }
     548             :                 | decl_varname K_ALIAS K_FOR decl_aliasitem ';'
     549             :                     {
     550          84 :                         plpgsql_ns_additem($4->itemtype,
     551          84 :                                            $4->itemno, $1.name);
     552             :                     }
     553             :                 | decl_varname opt_scrollable K_CURSOR
     554         122 :                     { 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         122 :                         plpgsql_ns_pop();
     561             : 
     562             :                         new = (PLpgSQL_var *)
     563         122 :                             plpgsql_build_variable($1.name, $1.lineno,
     564             :                                                    plpgsql_build_datatype(REFCURSOROID,
     565             :                                                                           -1,
     566             :                                                                           InvalidOid,
     567             :                                                                           NULL),
     568             :                                                    true);
     569             : 
     570         122 :                         new->cursor_explicit_expr = $7;
     571         122 :                         if ($5 == NULL)
     572          50 :                             new->cursor_explicit_argrow = -1;
     573             :                         else
     574          72 :                             new->cursor_explicit_argrow = $5->dno;
     575         122 :                         new->cursor_options = CURSOR_OPT_FAST_PLAN | $2;
     576             :                     }
     577             :                 ;
     578             : 
     579             : opt_scrollable :
     580             :                     {
     581         110 :                         $$ = 0;
     582             :                     }
     583             :                 | K_NO K_SCROLL
     584             :                     {
     585           6 :                         $$ = CURSOR_OPT_NO_SCROLL;
     586             :                     }
     587             :                 | K_SCROLL
     588             :                     {
     589           6 :                         $$ = CURSOR_OPT_SCROLL;
     590             :                     }
     591             :                 ;
     592             : 
     593             : decl_cursor_query :
     594             :                     {
     595         122 :                         $$ = read_sql_stmt(&yylval, &yylloc, yyscanner);
     596             :                     }
     597             :                 ;
     598             : 
     599             : decl_cursor_args :
     600             :                     {
     601          50 :                         $$ = NULL;
     602             :                     }
     603             :                 | '(' decl_cursor_arglist ')'
     604             :                     {
     605             :                         PLpgSQL_row *new;
     606             :                         int         i;
     607             :                         ListCell   *l;
     608             : 
     609          72 :                         new = palloc0_object(PLpgSQL_row);
     610          72 :                         new->dtype = PLPGSQL_DTYPE_ROW;
     611          72 :                         new->refname = "(unnamed row)";
     612          72 :                         new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
     613          72 :                         new->rowtupdesc = NULL;
     614          72 :                         new->nfields = list_length($2);
     615          72 :                         new->fieldnames = palloc_array(char *, new->nfields);
     616          72 :                         new->varnos = palloc_array(int, new->nfields);
     617             : 
     618          72 :                         i = 0;
     619         216 :                         foreach (l, $2)
     620             :                         {
     621         144 :                             PLpgSQL_variable *arg = (PLpgSQL_variable *) lfirst(l);
     622             :                             Assert(!arg->isconst);
     623         144 :                             new->fieldnames[i] = arg->refname;
     624         144 :                             new->varnos[i] = arg->dno;
     625         144 :                             i++;
     626             :                         }
     627          72 :                         list_free($2);
     628             : 
     629          72 :                         plpgsql_adddatum((PLpgSQL_datum *) new);
     630          72 :                         $$ = (PLpgSQL_datum *) new;
     631             :                     }
     632             :                 ;
     633             : 
     634             : decl_cursor_arglist : decl_cursor_arg
     635             :                     {
     636          72 :                         $$ = list_make1($1);
     637             :                     }
     638             :                 | decl_cursor_arglist ',' decl_cursor_arg
     639             :                     {
     640          72 :                         $$ = lappend($1, $3);
     641             :                     }
     642             :                 ;
     643             : 
     644             : decl_cursor_arg : decl_varname decl_datatype
     645             :                     {
     646         144 :                         $$ = (PLpgSQL_datum *)
     647         144 :                             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          84 :                         nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false,
     660          84 :                                                 $1.ident, NULL, NULL,
     661             :                                                 NULL);
     662          84 :                         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          84 :                         $$ = 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        6272 :                         $$.name = $1.ident;
     716        6272 :                         $$.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        6272 :                         if (plpgsql_ns_lookup(plpgsql_ns_top(), true,
     722        6272 :                                               $1.ident, NULL, NULL,
     723             :                                               NULL) != NULL)
     724           0 :                             yyerror(&yylloc, NULL, yyscanner, "duplicate declaration");
     725             : 
     726        6272 :                         if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR ||
     727        6200 :                             plpgsql_curr_compile->extra_errors & PLPGSQL_XCHECK_SHADOWVAR)
     728             :                         {
     729             :                             PLpgSQL_nsitem *nsi;
     730          72 :                             nsi = plpgsql_ns_lookup(plpgsql_ns_top(), false,
     731          72 :                                                     $1.ident, NULL, NULL, NULL);
     732          72 :                             if (nsi != NULL)
     733          54 :                                 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          32 :                         $$.name = pstrdup($1);
     744          32 :                         $$.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          32 :                         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          32 :                         if (plpgsql_curr_compile->extra_warnings & PLPGSQL_XCHECK_SHADOWVAR ||
     755          32 :                             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        5920 :                     { $$ = false; }
     773             :                 | K_CONSTANT
     774          28 :                     { $$ = 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        6092 :                         $$ = read_datatype(yychar, &yylval, &yylloc, yyscanner);
     785        6066 :                         yyclearin;
     786             :                     }
     787             :                 ;
     788             : 
     789             : decl_collate    :
     790        5898 :                     { $$ = InvalidOid; }
     791             :                 | K_COLLATE T_WORD
     792             :                     {
     793          24 :                         $$ = 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        5898 :                     { $$ = false; }
     809             :                 | K_NOT K_NULL
     810          24 :                     { $$ = true; }
     811             :                 ;
     812             : 
     813             : decl_defval     : ';'
     814        5110 :                     { $$ = NULL; }
     815             :                 | decl_defkey
     816             :                     {
     817         812 :                         $$ = 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       20404 :                     { $$ = NIL; }
     836             :                 | proc_sect proc_stmt
     837             :                     {
     838             :                         /* don't bother linking null statements into list */
     839       39540 :                         if ($2 == NULL)
     840          38 :                             $$ = $1;
     841             :                         else
     842       39502 :                             $$ = lappend($1, $2);
     843             :                     }
     844             :                 ;
     845             : 
     846             : proc_stmt       : pl_block ';'
     847         228 :                         { $$ = $1; }
     848             :                 | stmt_assign
     849        7764 :                         { $$ = $1; }
     850             :                 | stmt_if
     851        5990 :                         { $$ = $1; }
     852             :                 | stmt_case
     853          18 :                         { $$ = $1; }
     854             :                 | stmt_loop
     855          76 :                         { $$ = $1; }
     856             :                 | stmt_while
     857          80 :                         { $$ = $1; }
     858             :                 | stmt_for
     859        1528 :                         { $$ = $1; }
     860             :                 | stmt_foreach_a
     861          62 :                         { $$ = $1; }
     862             :                 | stmt_exit
     863         218 :                         { $$ = $1; }
     864             :                 | stmt_return
     865        9190 :                         { $$ = $1; }
     866             :                 | stmt_raise
     867        6992 :                         { $$ = $1; }
     868             :                 | stmt_assert
     869          54 :                         { $$ = $1; }
     870             :                 | stmt_execsql
     871        4086 :                         { $$ = $1; }
     872             :                 | stmt_dynexecute
     873        1126 :                         { $$ = $1; }
     874             :                 | stmt_perform
     875        1396 :                         { $$ = $1; }
     876             :                 | stmt_call
     877         108 :                         { $$ = $1; }
     878             :                 | stmt_getdiag
     879         136 :                         { $$ = $1; }
     880             :                 | stmt_open
     881         116 :                         { $$ = $1; }
     882             :                 | stmt_fetch
     883         122 :                         { $$ = $1; }
     884             :                 | stmt_move
     885          18 :                         { $$ = $1; }
     886             :                 | stmt_close
     887          66 :                         { $$ = $1; }
     888             :                 | stmt_null
     889          38 :                         { $$ = $1; }
     890             :                 | stmt_commit
     891          78 :                         { $$ = $1; }
     892             :                 | stmt_rollback
     893          50 :                         { $$ = $1; }
     894             :                 ;
     895             : 
     896             : stmt_perform    : K_PERFORM
     897             :                     {
     898             :                         PLpgSQL_stmt_perform *new;
     899             :                         int         startloc;
     900             : 
     901        1396 :                         new = palloc0_object(PLpgSQL_stmt_perform);
     902        1396 :                         new->cmd_type = PLPGSQL_STMT_PERFORM;
     903        1396 :                         new->lineno   = plpgsql_location_to_lineno(@1, yyscanner);
     904        1396 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
     905        1396 :                         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        1396 :                         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        1396 :                         memcpy(new->expr->query, " SELECT", 7);
     922             :                         /* left-justify to get rid of the leading space */
     923        1396 :                         memmove(new->expr->query, new->expr->query + 1,
     924        1396 :                                 strlen(new->expr->query));
     925             :                         /* offset syntax error position to account for that */
     926        1396 :                         check_sql_expr(new->expr->query, new->expr->parseMode,
     927             :                                        startloc + 1, yyscanner);
     928             : 
     929        1396 :                         $$ = (PLpgSQL_stmt *) new;
     930             :                     }
     931             :                 ;
     932             : 
     933             : stmt_call       : K_CALL
     934             :                     {
     935             :                         PLpgSQL_stmt_call *new;
     936             : 
     937         106 :                         new = palloc0_object(PLpgSQL_stmt_call);
     938         106 :                         new->cmd_type = PLPGSQL_STMT_CALL;
     939         106 :                         new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
     940         106 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
     941         106 :                         plpgsql_push_back_token(K_CALL, &yylval, &yylloc, yyscanner);
     942         106 :                         new->expr = read_sql_stmt(&yylval, &yylloc, yyscanner);
     943         106 :                         new->is_call = true;
     944             : 
     945             :                         /* Remember we may need a procedure resource owner */
     946         106 :                         plpgsql_curr_compile->requires_procedure_resowner = true;
     947             : 
     948         106 :                         $$ = (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           2 :                         new = palloc0_object(PLpgSQL_stmt_call);
     957           2 :                         new->cmd_type = PLPGSQL_STMT_CALL;
     958           2 :                         new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
     959           2 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
     960           2 :                         plpgsql_push_back_token(K_DO, &yylval, &yylloc, yyscanner);
     961           2 :                         new->expr = read_sql_stmt(&yylval, &yylloc, yyscanner);
     962           2 :                         new->is_call = false;
     963             : 
     964             :                         /* Remember we may need a procedure resource owner */
     965           2 :                         plpgsql_curr_compile->requires_procedure_resowner = true;
     966             : 
     967           2 :                         $$ = (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        7770 :                         switch ($1.ident ? 1 : list_length($1.idents))
     979             :                         {
     980        7076 :                             case 1:
     981        7076 :                                 pmode = RAW_PARSE_PLPGSQL_ASSIGN1;
     982        7076 :                                 break;
     983         680 :                             case 2:
     984         680 :                                 pmode = RAW_PARSE_PLPGSQL_ASSIGN2;
     985         680 :                                 break;
     986          14 :                             case 3:
     987          14 :                                 pmode = RAW_PARSE_PLPGSQL_ASSIGN3;
     988          14 :                                 break;
     989           0 :                             default:
     990           0 :                                 elog(ERROR, "unexpected number of names");
     991             :                                 pmode = 0; /* keep compiler quiet */
     992             :                         }
     993             : 
     994        7770 :                         check_assignable($1.datum, @1, yyscanner);
     995        7764 :                         new = palloc0_object(PLpgSQL_stmt_assign);
     996        7764 :                         new->cmd_type = PLPGSQL_STMT_ASSIGN;
     997        7764 :                         new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
     998        7764 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
     999        7764 :                         new->varno = $1.datum->dno;
    1000             :                         /* Push back the head name to include it in the stmt */
    1001        7764 :                         plpgsql_push_back_token(T_DATUM, &yylval, &yylloc, yyscanner);
    1002        7764 :                         new->expr = read_sql_construct(';', 0, 0, ";",
    1003             :                                                        pmode,
    1004             :                                                        false, true,
    1005             :                                                        NULL, NULL,
    1006             :                                                        &yylval, &yylloc, yyscanner);
    1007        7764 :                         mark_expr_as_assignment_source(new->expr, $1.datum);
    1008             : 
    1009        7764 :                         $$ = (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         136 :                         new = palloc0_object(PLpgSQL_stmt_getdiag);
    1019         136 :                         new->cmd_type = PLPGSQL_STMT_GETDIAG;
    1020         136 :                         new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
    1021         136 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    1022         136 :                         new->is_stacked = $2;
    1023         136 :                         new->diag_items = $4;
    1024             : 
    1025             :                         /*
    1026             :                          * Check information items are valid for area option.
    1027             :                          */
    1028         348 :                         foreach(lc, new->diag_items)
    1029             :                         {
    1030         212 :                             PLpgSQL_diag_item *ditem = (PLpgSQL_diag_item *) lfirst(lc);
    1031             : 
    1032         212 :                             switch (ditem->kind)
    1033             :                             {
    1034             :                                 /* these fields are disallowed in stacked case */
    1035          84 :                                 case PLPGSQL_GETDIAG_ROW_COUNT:
    1036             :                                 case PLPGSQL_GETDIAG_ROUTINE_OID:
    1037          84 :                                     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          84 :                                     break;
    1044             :                                 /* these fields are disallowed in current case */
    1045         104 :                                 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         104 :                                     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         104 :                                     break;
    1062             :                                 /* these fields are allowed in either case */
    1063          24 :                                 case PLPGSQL_GETDIAG_CONTEXT:
    1064          24 :                                     break;
    1065           0 :                                 default:
    1066           0 :                                     elog(ERROR, "unrecognized diagnostic item kind: %d",
    1067             :                                          ditem->kind);
    1068             :                                     break;
    1069             :                             }
    1070             :                         }
    1071             : 
    1072         136 :                         $$ = (PLpgSQL_stmt *) new;
    1073             :                     }
    1074             :                 ;
    1075             : 
    1076             : getdiag_area_opt :
    1077             :                     {
    1078         114 :                         $$ = false;
    1079             :                     }
    1080             :                 | K_CURRENT
    1081             :                     {
    1082           0 :                         $$ = false;
    1083             :                     }
    1084             :                 | K_STACKED
    1085             :                     {
    1086          28 :                         $$ = true;
    1087             :                     }
    1088             :                 ;
    1089             : 
    1090             : getdiag_list : getdiag_list ',' getdiag_list_item
    1091             :                     {
    1092          76 :                         $$ = lappend($1, $3);
    1093             :                     }
    1094             :                 | getdiag_list_item
    1095             :                     {
    1096         136 :                         $$ = list_make1($1);
    1097             :                     }
    1098             :                 ;
    1099             : 
    1100             : getdiag_list_item : getdiag_target assign_operator getdiag_item
    1101             :                     {
    1102             :                         PLpgSQL_diag_item *new;
    1103             : 
    1104         212 :                         new = palloc_object(PLpgSQL_diag_item);
    1105         212 :                         new->target = $1->dno;
    1106         212 :                         new->kind = $3;
    1107             : 
    1108         212 :                         $$ = new;
    1109             :                     }
    1110             :                 ;
    1111             : 
    1112             : getdiag_item :
    1113             :                     {
    1114         212 :                         int         tok = yylex(&yylval, &yylloc, yyscanner);
    1115             : 
    1116         212 :                         if (tok_is_keyword(tok, &yylval,
    1117             :                                            K_ROW_COUNT, "row_count"))
    1118          66 :                             $$ = PLPGSQL_GETDIAG_ROW_COUNT;
    1119         146 :                         else if (tok_is_keyword(tok, &yylval,
    1120             :                                                 K_PG_ROUTINE_OID, "pg_routine_oid"))
    1121          18 :                             $$ = PLPGSQL_GETDIAG_ROUTINE_OID;
    1122         128 :                         else if (tok_is_keyword(tok, &yylval,
    1123             :                                                 K_PG_CONTEXT, "pg_context"))
    1124          24 :                             $$ = PLPGSQL_GETDIAG_CONTEXT;
    1125         104 :                         else if (tok_is_keyword(tok, &yylval,
    1126             :                                                 K_PG_EXCEPTION_DETAIL, "pg_exception_detail"))
    1127          16 :                             $$ = PLPGSQL_GETDIAG_ERROR_DETAIL;
    1128          88 :                         else if (tok_is_keyword(tok, &yylval,
    1129             :                                                 K_PG_EXCEPTION_HINT, "pg_exception_hint"))
    1130          14 :                             $$ = PLPGSQL_GETDIAG_ERROR_HINT;
    1131          74 :                         else if (tok_is_keyword(tok, &yylval,
    1132             :                                                 K_PG_EXCEPTION_CONTEXT, "pg_exception_context"))
    1133           6 :                             $$ = PLPGSQL_GETDIAG_ERROR_CONTEXT;
    1134          68 :                         else if (tok_is_keyword(tok, &yylval,
    1135             :                                                 K_COLUMN_NAME, "column_name"))
    1136           8 :                             $$ = PLPGSQL_GETDIAG_COLUMN_NAME;
    1137          60 :                         else if (tok_is_keyword(tok, &yylval,
    1138             :                                                 K_CONSTRAINT_NAME, "constraint_name"))
    1139           8 :                             $$ = PLPGSQL_GETDIAG_CONSTRAINT_NAME;
    1140          52 :                         else if (tok_is_keyword(tok, &yylval,
    1141             :                                                 K_PG_DATATYPE_NAME, "pg_datatype_name"))
    1142           8 :                             $$ = PLPGSQL_GETDIAG_DATATYPE_NAME;
    1143          44 :                         else if (tok_is_keyword(tok, &yylval,
    1144             :                                                 K_MESSAGE_TEXT, "message_text"))
    1145          20 :                             $$ = PLPGSQL_GETDIAG_MESSAGE_TEXT;
    1146          24 :                         else if (tok_is_keyword(tok, &yylval,
    1147             :                                                 K_TABLE_NAME, "table_name"))
    1148           8 :                             $$ = PLPGSQL_GETDIAG_TABLE_NAME;
    1149          16 :                         else if (tok_is_keyword(tok, &yylval,
    1150             :                                                 K_SCHEMA_NAME, "schema_name"))
    1151           8 :                             $$ = PLPGSQL_GETDIAG_SCHEMA_NAME;
    1152           8 :                         else if (tok_is_keyword(tok, &yylval,
    1153             :                                                 K_RETURNED_SQLSTATE, "returned_sqlstate"))
    1154           8 :                             $$ = 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         218 :                         if ($1.datum->dtype == PLPGSQL_DTYPE_ROW ||
    1168         430 :                             $1.datum->dtype == PLPGSQL_DTYPE_REC ||
    1169         212 :                             plpgsql_peek(yyscanner) == '[')
    1170           6 :                             ereport(ERROR,
    1171             :                                     (errcode(ERRCODE_SYNTAX_ERROR),
    1172             :                                      errmsg("\"%s\" is not a scalar variable",
    1173             :                                             NameOfDatum(&($1))),
    1174             :                                      parser_errposition(@1)));
    1175         212 :                         check_assignable($1.datum, @1, yyscanner);
    1176         212 :                         $$ = $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        5990 :                         new = palloc0_object(PLpgSQL_stmt_if);
    1195        5990 :                         new->cmd_type = PLPGSQL_STMT_IF;
    1196        5990 :                         new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
    1197        5990 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    1198        5990 :                         new->cond = $2;
    1199        5990 :                         new->then_body = $3;
    1200        5990 :                         new->elsif_list = $4;
    1201        5990 :                         new->else_body = $5;
    1202             : 
    1203        5990 :                         $$ = (PLpgSQL_stmt *) new;
    1204             :                     }
    1205             :                 ;
    1206             : 
    1207             : stmt_elsifs     :
    1208             :                     {
    1209        5990 :                         $$ = NIL;
    1210             :                     }
    1211             :                 | stmt_elsifs K_ELSIF expr_until_then proc_sect
    1212             :                     {
    1213             :                         PLpgSQL_if_elsif *new;
    1214             : 
    1215        1158 :                         new = palloc0_object(PLpgSQL_if_elsif);
    1216        1158 :                         new->lineno = plpgsql_location_to_lineno(@2, yyscanner);
    1217        1158 :                         new->cond = $3;
    1218        1158 :                         new->stmts = $4;
    1219             : 
    1220        1158 :                         $$ = lappend($1, new);
    1221             :                     }
    1222             :                 ;
    1223             : 
    1224             : stmt_else       :
    1225             :                     {
    1226        4944 :                         $$ = NIL;
    1227             :                     }
    1228             :                 | K_ELSE proc_sect
    1229             :                     {
    1230        1046 :                         $$ = $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          18 :                         $$ = make_case(@1, $2, $3, $4, yyscanner);
    1237             :                     }
    1238             :                 ;
    1239             : 
    1240             : opt_expr_until_when :
    1241             :                     {
    1242          18 :                         PLpgSQL_expr *expr = NULL;
    1243          18 :                         int         tok = yylex(&yylval, &yylloc, yyscanner);
    1244             : 
    1245          18 :                         if (tok != K_WHEN)
    1246             :                         {
    1247          16 :                             plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
    1248          16 :                             expr = read_sql_expression(K_WHEN, "WHEN", &yylval, &yylloc, yyscanner);
    1249             :                         }
    1250          18 :                         plpgsql_push_back_token(K_WHEN, &yylval, &yylloc, yyscanner);
    1251          18 :                         $$ = expr;
    1252             :                     }
    1253             :                 ;
    1254             : 
    1255             : case_when_list  : case_when_list case_when
    1256             :                     {
    1257          22 :                         $$ = lappend($1, $2);
    1258             :                     }
    1259             :                 | case_when
    1260             :                     {
    1261          18 :                         $$ = list_make1($1);
    1262             :                     }
    1263             :                 ;
    1264             : 
    1265             : case_when       : K_WHEN expr_until_then proc_sect
    1266             :                     {
    1267          40 :                         PLpgSQL_case_when *new = palloc_object(PLpgSQL_case_when);
    1268             : 
    1269          40 :                         new->lineno  = plpgsql_location_to_lineno(@1, yyscanner);
    1270          40 :                         new->expr = $2;
    1271          40 :                         new->stmts = $3;
    1272          40 :                         $$ = new;
    1273             :                     }
    1274             :                 ;
    1275             : 
    1276             : opt_case_else   :
    1277             :                     {
    1278          14 :                         $$ = 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           4 :                         if ($2 != NIL)
    1289           4 :                             $$ = $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          76 :                         new = palloc0_object(PLpgSQL_stmt_loop);
    1300          76 :                         new->cmd_type = PLPGSQL_STMT_LOOP;
    1301          76 :                         new->lineno = plpgsql_location_to_lineno(@2, yyscanner);
    1302          76 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    1303          76 :                         new->label = $1;
    1304          76 :                         new->body = $3.stmts;
    1305             : 
    1306          76 :                         check_labels($1, $3.end_label, $3.end_label_location, yyscanner);
    1307          76 :                         plpgsql_ns_pop();
    1308             : 
    1309          76 :                         $$ = (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          80 :                         new = palloc0_object(PLpgSQL_stmt_while);
    1318          80 :                         new->cmd_type = PLPGSQL_STMT_WHILE;
    1319          80 :                         new->lineno = plpgsql_location_to_lineno(@2, yyscanner);
    1320          80 :                         new->stmtid  = ++plpgsql_curr_compile->nstatements;
    1321          80 :                         new->label = $1;
    1322          80 :                         new->cond = $3;
    1323          80 :                         new->body = $4.stmts;
    1324             : 
    1325          80 :                         check_labels($1, $4.end_label, $4.end_label_location, yyscanner);
    1326          80 :                         plpgsql_ns_pop();
    1327             : 
    1328          80 :                         $$ = (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        1534 :                         if ($3->cmd_type == PLPGSQL_STMT_FORI)
    1336             :                         {
    1337             :                             PLpgSQL_stmt_fori *new;
    1338             : 
    1339         790 :                             new = (PLpgSQL_stmt_fori *) $3;
    1340         790 :                             new->lineno = plpgsql_location_to_lineno(@2, yyscanner);
    1341         790 :                             new->label = $1;
    1342         790 :                             new->body = $4.stmts;
    1343         790 :                             $$ = (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         744 :                             new = (PLpgSQL_stmt_forq *) $3;
    1354         744 :                             new->lineno = plpgsql_location_to_lineno(@2, yyscanner);
    1355         744 :                             new->label = $1;
    1356         744 :                             new->body = $4.stmts;
    1357         744 :                             $$ = (PLpgSQL_stmt *) new;
    1358             :                         }
    1359             : 
    1360        1534 :                         check_labels($1, $4.end_label, $4.end_label_location, yyscanner);
    1361             :                         /* close namespace started in opt_loop_label */
    1362        1528 :                         plpgsql_ns_pop();
    1363             :                     }
    1364             :                 ;
    1365             : 
    1366             : for_control     : for_variable K_IN
    1367             :                     {
    1368        1546 :                         int         tok = yylex(&yylval, &yylloc, yyscanner);
    1369        1546 :                         int         tokloc = yylloc;
    1370             : 
    1371        1546 :                         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         292 :                             expr = read_sql_expression2(K_LOOP, K_USING,
    1380             :                                                         "LOOP or USING",
    1381             :                                                         &term, &yylval, &yylloc, yyscanner);
    1382             : 
    1383         292 :                             new = palloc0_object(PLpgSQL_stmt_dynfors);
    1384         292 :                             new->cmd_type = PLPGSQL_STMT_DYNFORS;
    1385         292 :                             new->stmtid = ++plpgsql_curr_compile->nstatements;
    1386         292 :                             if ($1.row)
    1387             :                             {
    1388          48 :                                 new->var = (PLpgSQL_variable *) $1.row;
    1389          48 :                                 check_assignable($1.row, @1, yyscanner);
    1390             :                             }
    1391         244 :                             else if ($1.scalar)
    1392             :                             {
    1393             :                                 /* convert single scalar to list */
    1394         244 :                                 new->var = (PLpgSQL_variable *)
    1395         244 :                                     make_scalar_list1($1.name, $1.scalar,
    1396         244 :                                                       $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         292 :                             new->query = expr;
    1407             : 
    1408         292 :                             if (term == K_USING)
    1409             :                             {
    1410             :                                 do
    1411             :                                 {
    1412          12 :                                     expr = read_sql_expression2(',', K_LOOP,
    1413             :                                                                 ", or LOOP",
    1414             :                                                                 &term, &yylval, &yylloc, yyscanner);
    1415          12 :                                     new->params = lappend(new->params, expr);
    1416          12 :                                 } while (term == ',');
    1417             :                             }
    1418             : 
    1419         292 :                             $$ = (PLpgSQL_stmt *) new;
    1420             :                         }
    1421        1254 :                         else if (tok == T_DATUM &&
    1422         144 :                                  yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_VAR &&
    1423         144 :                                  ((PLpgSQL_var *) yylval.wdatum.datum)->datatype->typoid == REFCURSOROID)
    1424          50 :                         {
    1425             :                             /* It's FOR var IN cursor */
    1426             :                             PLpgSQL_stmt_forc *new;
    1427          56 :                             PLpgSQL_var *cursor = (PLpgSQL_var *) yylval.wdatum.datum;
    1428             : 
    1429          56 :                             new = palloc0_object(PLpgSQL_stmt_forc);
    1430          56 :                             new->cmd_type = PLPGSQL_STMT_FORC;
    1431          56 :                             new->stmtid = ++plpgsql_curr_compile->nstatements;
    1432          56 :                             new->curvar = cursor->dno;
    1433             : 
    1434             :                             /* Should have had a single variable name */
    1435          56 :                             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          56 :                             if (cursor->cursor_explicit_expr == NULL)
    1443           6 :                                 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          50 :                             new->argquery = read_cursor_args(cursor, K_LOOP, &yylval, &yylloc, yyscanner);
    1450             : 
    1451             :                             /* create loop's private RECORD variable */
    1452          50 :                             new->var = (PLpgSQL_variable *)
    1453          50 :                                 plpgsql_build_record($1.name,
    1454          50 :                                                      $1.lineno,
    1455             :                                                      NULL,
    1456             :                                                      RECORDOID,
    1457             :                                                      true);
    1458             : 
    1459          50 :                             $$ = (PLpgSQL_stmt *) new;
    1460             :                         }
    1461             :                         else
    1462             :                         {
    1463             :                             PLpgSQL_expr *expr1;
    1464             :                             int         expr1loc;
    1465        1198 :                             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        1198 :                             if (tok_is_keyword(tok, &yylval,
    1480             :                                                K_REVERSE, "reverse"))
    1481           6 :                                 reverse = true;
    1482             :                             else
    1483        1192 :                                 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        1198 :                             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        1198 :                             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         790 :                                 expr1->parseMode = RAW_PARSE_PLPGSQL_EXPR;
    1516         790 :                                 check_sql_expr(expr1->query, expr1->parseMode,
    1517             :                                                expr1loc, yyscanner);
    1518             : 
    1519             :                                 /* Read and check the second one */
    1520         790 :                                 expr2 = read_sql_expression2(K_LOOP, K_BY,
    1521             :                                                              "LOOP",
    1522             :                                                              &tok, &yylval, &yylloc, yyscanner);
    1523             : 
    1524             :                                 /* Get the BY clause if any */
    1525         790 :                                 if (tok == K_BY)
    1526          18 :                                     expr_by = read_sql_expression(K_LOOP,
    1527             :                                                                   "LOOP", &yylval, &yylloc, yyscanner);
    1528             :                                 else
    1529         772 :                                     expr_by = NULL;
    1530             : 
    1531             :                                 /* Should have had a single variable name */
    1532         790 :                                 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         790 :                                     plpgsql_build_variable($1.name,
    1541         790 :                                                            $1.lineno,
    1542             :                                                            plpgsql_build_datatype(INT4OID,
    1543             :                                                                                   -1,
    1544             :                                                                                   InvalidOid,
    1545             :                                                                                   NULL),
    1546             :                                                            true);
    1547             : 
    1548         790 :                                 new = palloc0_object(PLpgSQL_stmt_fori);
    1549         790 :                                 new->cmd_type = PLPGSQL_STMT_FORI;
    1550         790 :                                 new->stmtid  = ++plpgsql_curr_compile->nstatements;
    1551         790 :                                 new->var = fvar;
    1552         790 :                                 new->reverse = reverse;
    1553         790 :                                 new->lower = expr1;
    1554         790 :                                 new->upper = expr2;
    1555         790 :                                 new->step = expr_by;
    1556             : 
    1557         790 :                                 $$ = (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         408 :                                 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         408 :                                 check_sql_expr(expr1->query, expr1->parseMode,
    1574             :                                                expr1loc, yyscanner);
    1575             : 
    1576         402 :                                 new = palloc0_object(PLpgSQL_stmt_fors);
    1577         402 :                                 new->cmd_type = PLPGSQL_STMT_FORS;
    1578         402 :                                 new->stmtid = ++plpgsql_curr_compile->nstatements;
    1579         402 :                                 if ($1.row)
    1580             :                                 {
    1581         268 :                                     new->var = (PLpgSQL_variable *) $1.row;
    1582         268 :                                     check_assignable($1.row, @1, yyscanner);
    1583             :                                 }
    1584         134 :                                 else if ($1.scalar)
    1585             :                                 {
    1586             :                                     /* convert single scalar to list */
    1587         134 :                                     new->var = (PLpgSQL_variable *)
    1588         134 :                                         make_scalar_list1($1.name, $1.scalar,
    1589         134 :                                                           $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         402 :                                 new->query = expr1;
    1601         402 :                                 $$ = (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         794 :                         $$.name = NameOfDatum(&($1));
    1628         794 :                         $$.lineno = plpgsql_location_to_lineno(@1, yyscanner);
    1629         794 :                         if ($1.datum->dtype == PLPGSQL_DTYPE_ROW ||
    1630         794 :                             $1.datum->dtype == PLPGSQL_DTYPE_REC)
    1631             :                         {
    1632         330 :                             $$.scalar = NULL;
    1633         330 :                             $$.row = $1.datum;
    1634             :                         }
    1635             :                         else
    1636             :                         {
    1637             :                             int         tok;
    1638             : 
    1639         464 :                             $$.scalar = $1.datum;
    1640         464 :                             $$.row = NULL;
    1641             :                             /* check for comma-separated list */
    1642         464 :                             tok = yylex(&yylval, &yylloc, yyscanner);
    1643         464 :                             plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
    1644         464 :                             if (tok == ',')
    1645          16 :                                 $$.row = (PLpgSQL_datum *)
    1646          20 :                                     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         820 :                         $$.name = $1.ident;
    1658         820 :                         $$.lineno = plpgsql_location_to_lineno(@1, yyscanner);
    1659         820 :                         $$.scalar = NULL;
    1660         820 :                         $$.row = NULL;
    1661             :                         /* check for comma-separated list */
    1662         820 :                         tok = yylex(&yylval, &yylloc, yyscanner);
    1663         820 :                         plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
    1664         820 :                         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          62 :                         new = palloc0_object(PLpgSQL_stmt_foreach_a);
    1679          62 :                         new->cmd_type = PLPGSQL_STMT_FOREACH_A;
    1680          62 :                         new->lineno = plpgsql_location_to_lineno(@2, yyscanner);
    1681          62 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    1682          62 :                         new->label = $1;
    1683          62 :                         new->slice = $4;
    1684          62 :                         new->expr = $7;
    1685          62 :                         new->body = $8.stmts;
    1686             : 
    1687          62 :                         if ($3.row)
    1688             :                         {
    1689          24 :                             new->varno = $3.row->dno;
    1690          24 :                             check_assignable($3.row, @3, yyscanner);
    1691             :                         }
    1692          38 :                         else if ($3.scalar)
    1693             :                         {
    1694          38 :                             new->varno = $3.scalar->dno;
    1695          38 :                             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          62 :                         check_labels($1, $8.end_label, $8.end_label_location, yyscanner);
    1706          62 :                         plpgsql_ns_pop();
    1707             : 
    1708          62 :                         $$ = (PLpgSQL_stmt *) new;
    1709             :                     }
    1710             :                 ;
    1711             : 
    1712             : foreach_slice   :
    1713             :                     {
    1714          32 :                         $$ = 0;
    1715             :                     }
    1716             :                 | K_SLICE ICONST
    1717             :                     {
    1718          30 :                         $$ = $2;
    1719             :                     }
    1720             :                 ;
    1721             : 
    1722             : stmt_exit       : exit_type opt_label opt_exitcond
    1723             :                     {
    1724             :                         PLpgSQL_stmt_exit *new;
    1725             : 
    1726         228 :                         new = palloc0_object(PLpgSQL_stmt_exit);
    1727         228 :                         new->cmd_type = PLPGSQL_STMT_EXIT;
    1728         228 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    1729         228 :                         new->is_exit = $1;
    1730         228 :                         new->lineno  = plpgsql_location_to_lineno(@1, yyscanner);
    1731         228 :                         new->label = $2;
    1732         228 :                         new->cond = $3;
    1733             : 
    1734         228 :                         if ($2)
    1735             :                         {
    1736             :                             /* We have a label, so verify it exists */
    1737             :                             PLpgSQL_nsitem *label;
    1738             : 
    1739          32 :                             label = plpgsql_ns_lookup_label(plpgsql_ns_top(), $2);
    1740          32 :                             if (label == NULL)
    1741           4 :                                 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          28 :                             if (label->itemno != PLPGSQL_LABEL_LOOP && !new->is_exit)
    1749           2 :                                 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         196 :                             if (plpgsql_ns_find_nearest_loop(plpgsql_ns_top()) == NULL)
    1763           4 :                                 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         218 :                         $$ = (PLpgSQL_stmt *) new;
    1772             :                     }
    1773             :                 ;
    1774             : 
    1775             : exit_type       : K_EXIT
    1776             :                     {
    1777         118 :                         $$ = true;
    1778             :                     }
    1779             :                 | K_CONTINUE
    1780             :                     {
    1781         110 :                         $$ = false;
    1782             :                     }
    1783             :                 ;
    1784             : 
    1785             : stmt_return     : K_RETURN
    1786             :                     {
    1787             :                         int         tok;
    1788             : 
    1789        9216 :                         tok = yylex(&yylval, &yylloc, yyscanner);
    1790        9216 :                         if (tok == 0)
    1791           0 :                             yyerror(&yylloc, NULL, yyscanner, "unexpected end of function definition");
    1792             : 
    1793        9216 :                         if (tok_is_keyword(tok, &yylval,
    1794             :                                            K_NEXT, "next"))
    1795             :                         {
    1796         354 :                             $$ = make_return_next_stmt(@1, &yylval, &yylloc, yyscanner);
    1797             :                         }
    1798        8862 :                         else if (tok_is_keyword(tok, &yylval,
    1799             :                                                 K_QUERY, "query"))
    1800             :                         {
    1801         176 :                             $$ = make_return_query_stmt(@1, &yylval, &yylloc, yyscanner);
    1802             :                         }
    1803             :                         else
    1804             :                         {
    1805        8686 :                             plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
    1806        8686 :                             $$ = 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        7004 :                         new = palloc_object(PLpgSQL_stmt_raise);
    1817             : 
    1818        7004 :                         new->cmd_type = PLPGSQL_STMT_RAISE;
    1819        7004 :                         new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
    1820        7004 :                         new->stmtid  = ++plpgsql_curr_compile->nstatements;
    1821        7004 :                         new->elog_level = ERROR; /* default */
    1822        7004 :                         new->condname = NULL;
    1823        7004 :                         new->message = NULL;
    1824        7004 :                         new->params = NIL;
    1825        7004 :                         new->options = NIL;
    1826             : 
    1827        7004 :                         tok = yylex(&yylval, &yylloc, yyscanner);
    1828        7004 :                         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        7004 :                         if (tok != ';')
    1836             :                         {
    1837             :                             /*
    1838             :                              * First is an optional elog severity level.
    1839             :                              */
    1840        6960 :                             if (tok_is_keyword(tok, &yylval,
    1841             :                                                K_EXCEPTION, "exception"))
    1842             :                             {
    1843         854 :                                 new->elog_level = ERROR;
    1844         854 :                                 tok = yylex(&yylval, &yylloc, yyscanner);
    1845             :                             }
    1846        6106 :                             else if (tok_is_keyword(tok, &yylval,
    1847             :                                                     K_WARNING, "warning"))
    1848             :                             {
    1849         206 :                                 new->elog_level = WARNING;
    1850         206 :                                 tok = yylex(&yylval, &yylloc, yyscanner);
    1851             :                             }
    1852        5900 :                             else if (tok_is_keyword(tok, &yylval,
    1853             :                                                     K_NOTICE, "notice"))
    1854             :                             {
    1855        5260 :                                 new->elog_level = NOTICE;
    1856        5260 :                                 tok = yylex(&yylval, &yylloc, yyscanner);
    1857             :                             }
    1858         640 :                             else if (tok_is_keyword(tok, &yylval,
    1859             :                                                     K_INFO, "info"))
    1860             :                             {
    1861         244 :                                 new->elog_level = INFO;
    1862         244 :                                 tok = yylex(&yylval, &yylloc, yyscanner);
    1863             :                             }
    1864         396 :                             else if (tok_is_keyword(tok, &yylval,
    1865             :                                                     K_LOG, "log"))
    1866             :                             {
    1867         144 :                                 new->elog_level = LOG;
    1868         144 :                                 tok = yylex(&yylval, &yylloc, yyscanner);
    1869             :                             }
    1870         252 :                             else if (tok_is_keyword(tok, &yylval,
    1871             :                                                     K_DEBUG, "debug"))
    1872             :                             {
    1873          58 :                                 new->elog_level = DEBUG1;
    1874          58 :                                 tok = yylex(&yylval, &yylloc, yyscanner);
    1875             :                             }
    1876        6960 :                             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        6960 :                             if (tok == SCONST)
    1886             :                             {
    1887             :                                 /* old style message and parameters */
    1888        6796 :                                 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        6796 :                                 tok = yylex(&yylval, &yylloc, yyscanner);
    1896        6796 :                                 if (tok != ',' && tok != ';' && tok != K_USING)
    1897           0 :                                     yyerror(&yylloc, NULL, yyscanner, "syntax error");
    1898             : 
    1899       21732 :                                 while (tok == ',')
    1900             :                                 {
    1901             :                                     PLpgSQL_expr *expr;
    1902             : 
    1903       14936 :                                     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       14936 :                                     new->params = lappend(new->params, expr);
    1910             :                                 }
    1911             :                             }
    1912         164 :                             else if (tok != K_USING)
    1913             :                             {
    1914             :                                 /* must be condition name or SQLSTATE */
    1915         146 :                                 if (tok_is_keyword(tok, &yylval,
    1916             :                                                    K_SQLSTATE, "sqlstate"))
    1917             :                                 {
    1918             :                                     /* next token should be a string literal */
    1919             :                                     char       *sqlstatestr;
    1920             : 
    1921         104 :                                     if (yylex(&yylval, &yylloc, yyscanner) != SCONST)
    1922           0 :                                         yyerror(&yylloc, NULL, yyscanner, "syntax error");
    1923         104 :                                     sqlstatestr = yylval.str;
    1924             : 
    1925         104 :                                     if (strlen(sqlstatestr) != 5)
    1926           0 :                                         yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code");
    1927         104 :                                     if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5)
    1928           0 :                                         yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code");
    1929         104 :                                     new->condname = sqlstatestr;
    1930             :                                 }
    1931             :                                 else
    1932             :                                 {
    1933          42 :                                     if (tok == T_WORD)
    1934          42 :                                         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          42 :                                     plpgsql_recognize_err_condition(new->condname,
    1940             :                                                                     false);
    1941             :                                 }
    1942         146 :                                 tok = yylex(&yylval, &yylloc, yyscanner);
    1943         146 :                                 if (tok != ';' && tok != K_USING)
    1944           0 :                                     yyerror(&yylloc, NULL, yyscanner, "syntax error");
    1945             :                             }
    1946             : 
    1947        6960 :                             if (tok == K_USING)
    1948         180 :                                 new->options = read_raise_options(&yylval, &yylloc, yyscanner);
    1949             :                         }
    1950             : 
    1951        7004 :                         check_raise_parameters(new);
    1952             : 
    1953        6992 :                         $$ = (PLpgSQL_stmt *) new;
    1954             :                     }
    1955             :                 ;
    1956             : 
    1957             : stmt_assert     : K_ASSERT
    1958             :                     {
    1959             :                         PLpgSQL_stmt_assert *new;
    1960             :                         int         tok;
    1961             : 
    1962          54 :                         new = palloc_object(PLpgSQL_stmt_assert);
    1963             : 
    1964          54 :                         new->cmd_type = PLPGSQL_STMT_ASSERT;
    1965          54 :                         new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
    1966          54 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    1967             : 
    1968          54 :                         new->cond = read_sql_expression2(',', ';',
    1969             :                                                          ", or ;",
    1970             :                                                          &tok, &yylval, &yylloc, yyscanner);
    1971             : 
    1972          54 :                         if (tok == ',')
    1973          20 :                             new->message = read_sql_expression(';', ";", &yylval, &yylloc, yyscanner);
    1974             :                         else
    1975          34 :                             new->message = NULL;
    1976             : 
    1977          54 :                         $$ = (PLpgSQL_stmt *) new;
    1978             :                     }
    1979             :                 ;
    1980             : 
    1981             : loop_body       : proc_sect K_END K_LOOP opt_label ';'
    1982             :                     {
    1983        1752 :                         $$.stmts = $1;
    1984        1752 :                         $$.end_label = $4;
    1985        1752 :                         $$.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         918 :                         $$ = make_execsql_stmt(K_INSERT, @1, NULL, &yylval, &yylloc, yyscanner);
    2006             :                     }
    2007             :                 | K_MERGE
    2008             :                     {
    2009          54 :                         $$ = make_execsql_stmt(K_MERGE, @1, NULL, &yylval, &yylloc, yyscanner);
    2010             :                     }
    2011             :                 | T_WORD
    2012             :                     {
    2013             :                         int         tok;
    2014             : 
    2015        3120 :                         tok = yylex(&yylval, &yylloc, yyscanner);
    2016        3120 :                         plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
    2017        3120 :                         if (tok == '=' || tok == COLON_EQUALS ||
    2018        3120 :                             tok == '[' || tok == '.')
    2019           0 :                             word_is_not_variable(&($1), @1, yyscanner);
    2020        3120 :                         $$ = make_execsql_stmt(T_WORD, @1, &($1), &yylval, &yylloc, yyscanner);
    2021             :                     }
    2022             :                 | T_CWORD
    2023             :                     {
    2024             :                         int         tok;
    2025             : 
    2026           4 :                         tok = yylex(&yylval, &yylloc, yyscanner);
    2027           4 :                         plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
    2028           4 :                         if (tok == '=' || tok == COLON_EQUALS ||
    2029           2 :                             tok == '[' || tok == '.')
    2030           4 :                             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        1126 :                         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        1126 :                         new = palloc_object(PLpgSQL_stmt_dynexecute);
    2049        1126 :                         new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;
    2050        1126 :                         new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
    2051        1126 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    2052        1126 :                         new->query = expr;
    2053        1126 :                         new->into = false;
    2054        1126 :                         new->strict = false;
    2055        1126 :                         new->target = NULL;
    2056        1126 :                         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        2082 :                             if (endtoken == K_INTO)
    2068             :                             {
    2069         574 :                                 if (new->into)           /* multiple INTO */
    2070           0 :                                     yyerror(&yylloc, NULL, yyscanner, "syntax error");
    2071         574 :                                 new->into = true;
    2072         574 :                                 read_into_target(&new->target, &new->strict, &yylval, &yylloc, yyscanner);
    2073         574 :                                 endtoken = yylex(&yylval, &yylloc, yyscanner);
    2074             :                             }
    2075        1508 :                             else if (endtoken == K_USING)
    2076             :                             {
    2077         382 :                                 if (new->params)     /* multiple USING */
    2078           0 :                                     yyerror(&yylloc, NULL, yyscanner, "syntax error");
    2079             :                                 do
    2080             :                                 {
    2081         758 :                                     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         758 :                                     new->params = lappend(new->params, expr);
    2088         758 :                                 } while (endtoken == ',');
    2089             :                             }
    2090        1126 :                             else if (endtoken == ';')
    2091        1126 :                                 break;
    2092             :                             else
    2093           0 :                                 yyerror(&yylloc, NULL, yyscanner, "syntax error");
    2094             :                         }
    2095             : 
    2096        1126 :                         $$ = (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         140 :                         new = palloc0_object(PLpgSQL_stmt_open);
    2107         140 :                         new->cmd_type = PLPGSQL_STMT_OPEN;
    2108         140 :                         new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
    2109         140 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    2110         140 :                         new->curvar = $2->dno;
    2111         140 :                         new->cursor_options = CURSOR_OPT_FAST_PLAN;
    2112             : 
    2113         140 :                         if ($2->cursor_explicit_expr == NULL)
    2114             :                         {
    2115             :                             /* be nice if we could use opt_scrollable here */
    2116          56 :                             tok = yylex(&yylval, &yylloc, yyscanner);
    2117          56 :                             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          56 :                             else if (tok_is_keyword(tok, &yylval,
    2129             :                                                     K_SCROLL, "scroll"))
    2130             :                             {
    2131          20 :                                 new->cursor_options |= CURSOR_OPT_SCROLL;
    2132          20 :                                 tok = yylex(&yylval, &yylloc, yyscanner);
    2133             :                             }
    2134             : 
    2135          56 :                             if (tok != K_FOR)
    2136           0 :                                 yyerror(&yylloc, NULL, yyscanner, "syntax error, expected \"FOR\"");
    2137             : 
    2138          56 :                             tok = yylex(&yylval, &yylloc, yyscanner);
    2139          56 :                             if (tok_is_keyword(tok, &yylval,
    2140             :                                                K_EXECUTE, "execute"))
    2141             :                             {
    2142             :                                 int         endtoken;
    2143             : 
    2144          18 :                                 new->dynquery =
    2145          18 :                                     read_sql_expression2(K_USING, ';',
    2146             :                                                          "USING or ;",
    2147             :                                                          &endtoken, &yylval, &yylloc, yyscanner);
    2148             : 
    2149             :                                 /* If we found "USING", collect argument(s) */
    2150          18 :                                 if (endtoken == K_USING)
    2151             :                                 {
    2152             :                                     PLpgSQL_expr *expr;
    2153             : 
    2154             :                                     do
    2155             :                                     {
    2156           6 :                                         expr = read_sql_expression2(',', ';',
    2157             :                                                                     ", or ;",
    2158             :                                                                     &endtoken, &yylval, &yylloc, yyscanner);
    2159           6 :                                         new->params = lappend(new->params,
    2160             :                                                               expr);
    2161           6 :                                     } while (endtoken == ',');
    2162             :                                 }
    2163             :                             }
    2164             :                             else
    2165             :                             {
    2166          38 :                                 plpgsql_push_back_token(tok, &yylval, &yylloc, yyscanner);
    2167          38 :                                 new->query = read_sql_stmt(&yylval, &yylloc, yyscanner);
    2168             :                             }
    2169             :                         }
    2170             :                         else
    2171             :                         {
    2172             :                             /* predefined cursor query, so read args */
    2173          84 :                             new->argquery = read_cursor_args($2, ';', &yylval, &yylloc, yyscanner);
    2174             :                         }
    2175             : 
    2176         116 :                         $$ = (PLpgSQL_stmt *) new;
    2177             :                     }
    2178             :                 ;
    2179             : 
    2180             : stmt_fetch      : K_FETCH opt_fetch_direction cursor_variable K_INTO
    2181             :                     {
    2182         122 :                         PLpgSQL_stmt_fetch *fetch = $2;
    2183             :                         PLpgSQL_variable *target;
    2184             : 
    2185             :                         /* We have already parsed everything through the INTO keyword */
    2186         122 :                         read_into_target(&target, NULL, &yylval, &yylloc, yyscanner);
    2187             : 
    2188         122 :                         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         122 :                         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         122 :                         fetch->lineno = plpgsql_location_to_lineno(@1, yyscanner);
    2202         122 :                         fetch->target    = target;
    2203         122 :                         fetch->curvar    = $3->dno;
    2204         122 :                         fetch->is_move   = false;
    2205             : 
    2206         122 :                         $$ = (PLpgSQL_stmt *) fetch;
    2207             :                     }
    2208             :                 ;
    2209             : 
    2210             : stmt_move       : K_MOVE opt_fetch_direction cursor_variable ';'
    2211             :                     {
    2212          18 :                         PLpgSQL_stmt_fetch *fetch = $2;
    2213             : 
    2214          18 :                         fetch->lineno = plpgsql_location_to_lineno(@1, yyscanner);
    2215          18 :                         fetch->curvar = $3->dno;
    2216          18 :                         fetch->is_move = true;
    2217             : 
    2218          18 :                         $$ = (PLpgSQL_stmt *) fetch;
    2219             :                     }
    2220             :                 ;
    2221             : 
    2222             : opt_fetch_direction :
    2223             :                     {
    2224         140 :                         $$ = read_fetch_direction(&yylval, &yylloc, yyscanner);
    2225             :                     }
    2226             :                 ;
    2227             : 
    2228             : stmt_close      : K_CLOSE cursor_variable ';'
    2229             :                     {
    2230             :                         PLpgSQL_stmt_close *new;
    2231             : 
    2232          66 :                         new = palloc_object(PLpgSQL_stmt_close);
    2233          66 :                         new->cmd_type = PLPGSQL_STMT_CLOSE;
    2234          66 :                         new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
    2235          66 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    2236          66 :                         new->curvar = $2->dno;
    2237             : 
    2238          66 :                         $$ = (PLpgSQL_stmt *) new;
    2239             :                     }
    2240             :                 ;
    2241             : 
    2242             : stmt_null       : K_NULL ';'
    2243             :                     {
    2244             :                         /* We do not bother building a node for NULL */
    2245          38 :                         $$ = NULL;
    2246             :                     }
    2247             :                 ;
    2248             : 
    2249             : stmt_commit     : K_COMMIT opt_transaction_chain ';'
    2250             :                     {
    2251             :                         PLpgSQL_stmt_commit *new;
    2252             : 
    2253          78 :                         new = palloc_object(PLpgSQL_stmt_commit);
    2254          78 :                         new->cmd_type = PLPGSQL_STMT_COMMIT;
    2255          78 :                         new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
    2256          78 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    2257          78 :                         new->chain = $2;
    2258             : 
    2259          78 :                         $$ = (PLpgSQL_stmt *) new;
    2260             :                     }
    2261             :                 ;
    2262             : 
    2263             : stmt_rollback   : K_ROLLBACK opt_transaction_chain ';'
    2264             :                     {
    2265             :                         PLpgSQL_stmt_rollback *new;
    2266             : 
    2267          50 :                         new = palloc_object(PLpgSQL_stmt_rollback);
    2268          50 :                         new->cmd_type = PLPGSQL_STMT_ROLLBACK;
    2269          50 :                         new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
    2270          50 :                         new->stmtid = ++plpgsql_curr_compile->nstatements;
    2271          50 :                         new->chain = $2;
    2272             : 
    2273          50 :                         $$ = (PLpgSQL_stmt *) new;
    2274             :                     }
    2275             :                 ;
    2276             : 
    2277             : opt_transaction_chain:
    2278           4 :             K_AND K_CHAIN           { $$ = true; }
    2279           0 :             | K_AND K_NO K_CHAIN    { $$ = false; }
    2280         124 :             | /* 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         692 :                         if ($1.datum->dtype != PLPGSQL_DTYPE_VAR ||
    2292         346 :                             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         346 :                         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         346 :                         $$ = (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        9348 :                     { $$ = 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         460 :                         int         lineno = plpgsql_location_to_lineno(@1, yyscanner);
    2330         460 :                         PLpgSQL_exception_block *new = palloc_object(PLpgSQL_exception_block);
    2331             :                         PLpgSQL_variable *var;
    2332             : 
    2333         460 :                         plpgsql_curr_compile->has_exception_block = true;
    2334             : 
    2335         460 :                         var = plpgsql_build_variable("sqlstate", lineno,
    2336             :                                                      plpgsql_build_datatype(TEXTOID,
    2337             :                                                                             -1,
    2338         460 :                                                                             plpgsql_curr_compile->fn_input_collation,
    2339             :                                                                             NULL),
    2340             :                                                      true);
    2341         460 :                         var->isconst = true;
    2342         460 :                         new->sqlstate_varno = var->dno;
    2343             : 
    2344         460 :                         var = plpgsql_build_variable("sqlerrm", lineno,
    2345             :                                                      plpgsql_build_datatype(TEXTOID,
    2346             :                                                                             -1,
    2347         460 :                                                                             plpgsql_curr_compile->fn_input_collation,
    2348             :                                                                             NULL),
    2349             :                                                      true);
    2350         460 :                         var->isconst = true;
    2351         460 :                         new->sqlerrm_varno = var->dno;
    2352             : 
    2353         460 :                         $<exception_block>$ = new;
    2354             :                     }
    2355             :                     proc_exceptions
    2356             :                     {
    2357         460 :                         PLpgSQL_exception_block *new = $<exception_block>2;
    2358         460 :                         new->exc_list = $3;
    2359             : 
    2360         460 :                         $$ = new;
    2361             :                     }
    2362             :                 ;
    2363             : 
    2364             : proc_exceptions : proc_exceptions proc_exception
    2365             :                         {
    2366          12 :                             $$ = lappend($1, $2);
    2367             :                         }
    2368             :                 | proc_exception
    2369             :                         {
    2370         460 :                             $$ = list_make1($1);
    2371             :                         }
    2372             :                 ;
    2373             : 
    2374             : proc_exception  : K_WHEN proc_conditions K_THEN proc_sect
    2375             :                     {
    2376             :                         PLpgSQL_exception *new;
    2377             : 
    2378         472 :                         new = palloc0_object(PLpgSQL_exception);
    2379         472 :                         new->lineno = plpgsql_location_to_lineno(@1, yyscanner);
    2380         472 :                         new->conditions = $2;
    2381         472 :                         new->action = $4;
    2382             : 
    2383         472 :                         $$ = new;
    2384             :                     }
    2385             :                 ;
    2386             : 
    2387             : proc_conditions : proc_conditions K_OR proc_condition
    2388             :                         {
    2389             :                             PLpgSQL_condition   *old;
    2390             : 
    2391          20 :                             for (old = $1; old->next != NULL; old = old->next)
    2392             :                                 /* skip */ ;
    2393          14 :                             old->next = $3;
    2394          14 :                             $$ = $1;
    2395             :                         }
    2396             :                 | proc_condition
    2397             :                         {
    2398         472 :                             $$ = $1;
    2399             :                         }
    2400             :                 ;
    2401             : 
    2402             : proc_condition  : any_identifier
    2403             :                         {
    2404         486 :                             if (strcmp($1, "sqlstate") != 0)
    2405             :                             {
    2406         458 :                                 $$ = 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          28 :                                 if (yylex(&yylval, &yylloc, yyscanner) != SCONST)
    2415           0 :                                     yyerror(&yylloc, NULL, yyscanner, "syntax error");
    2416          28 :                                 sqlstatestr = yylval.str;
    2417             : 
    2418          28 :                                 if (strlen(sqlstatestr) != 5)
    2419           0 :                                     yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code");
    2420          28 :                                 if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5)
    2421           0 :                                     yyerror(&yylloc, NULL, yyscanner, "invalid SQLSTATE code");
    2422             : 
    2423          28 :                                 new = palloc_object(PLpgSQL_condition);
    2424          28 :                                 new->sqlerrstate =
    2425          28 :                                     MAKE_SQLSTATE(sqlstatestr[0],
    2426             :                                                   sqlstatestr[1],
    2427             :                                                   sqlstatestr[2],
    2428             :                                                   sqlstatestr[3],
    2429             :                                                   sqlstatestr[4]);
    2430          28 :                                 new->condname = sqlstatestr;
    2431          28 :                                 new->next = NULL;
    2432             : 
    2433          28 :                                 $$ = new;
    2434             :                             }
    2435             :                         }
    2436             :                 ;
    2437             : 
    2438             : expr_until_semi :
    2439         144 :                     { $$ = read_sql_expression(';', ";", &yylval, &yylloc, yyscanner); }
    2440             :                 ;
    2441             : 
    2442             : expr_until_then :
    2443        7188 :                     { $$ = read_sql_expression(K_THEN, "THEN", &yylval, &yylloc, yyscanner); }
    2444             :                 ;
    2445             : 
    2446             : expr_until_loop :
    2447         142 :                     { $$ = read_sql_expression(K_LOOP, "LOOP", &yylval, &yylloc, yyscanner); }
    2448             :                 ;
    2449             : 
    2450             : opt_block_label :
    2451             :                     {
    2452        9916 :                         plpgsql_ns_push(NULL, PLPGSQL_LABEL_BLOCK);
    2453        9916 :                         $$ = NULL;
    2454             :                     }
    2455             :                 | LESS_LESS any_identifier GREATER_GREATER
    2456             :                     {
    2457          62 :                         plpgsql_ns_push($2, PLPGSQL_LABEL_BLOCK);
    2458          62 :                         $$ = $2;
    2459             :                     }
    2460             :                 ;
    2461             : 
    2462             : opt_loop_label  :
    2463             :                     {
    2464        1746 :                         plpgsql_ns_push(NULL, PLPGSQL_LABEL_LOOP);
    2465        1746 :                         $$ = NULL;
    2466             :                     }
    2467             :                 | LESS_LESS any_identifier GREATER_GREATER
    2468             :                     {
    2469          30 :                         plpgsql_ns_push($2, PLPGSQL_LABEL_LOOP);
    2470          30 :                         $$ = $2;
    2471             :                     }
    2472             :                 ;
    2473             : 
    2474             : opt_label   :
    2475             :                     {
    2476       11746 :                         $$ = NULL;
    2477             :                     }
    2478             :                 | any_identifier
    2479             :                     {
    2480             :                         /* label validity will be checked by outer production */
    2481          42 :                         $$ = $1;
    2482             :                     }
    2483             :                 ;
    2484             : 
    2485             : opt_exitcond    : ';'
    2486          84 :                     { $$ = NULL; }
    2487             :                 | K_WHEN expr_until_semi
    2488         144 :                     { $$ = $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         592 :                         $$ = $1.ident;
    2497             :                     }
    2498             :                 | unreserved_keyword
    2499             :                     {
    2500           0 :                         $$ = pstrdup($1);
    2501             :                     }
    2502             :                 | T_DATUM
    2503             :                     {
    2504          28 :                         if ($1.ident == NULL) /* composite name not OK */
    2505           0 :                             yyerror(&yylloc, NULL, yyscanner, "syntax error");
    2506          28 :                         $$ = $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       46266 : tok_is_keyword(int token, union YYSTYPE *lval,
    2607             :                int kw_token, const char *kw_str)
    2608             : {
    2609       46266 :     if (token == kw_token)
    2610             :     {
    2611             :         /* Normal case, was recognized by scanner (no conflicting variable) */
    2612        8722 :         return true;
    2613             :     }
    2614       37544 :     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       12734 :         if (!lval->wdatum.quoted && lval->wdatum.ident != NULL &&
    2622       12510 :             strcmp(lval->wdatum.ident, kw_str) == 0)
    2623           6 :             return true;
    2624             :     }
    2625       37538 :     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           4 : cword_is_not_variable(PLcword *cword, int location, yyscan_t yyscanner)
    2645             : {
    2646           4 :     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       45398 : make_plpgsql_expr(const char *query,
    2672             :                   RawParseMode parsemode)
    2673             : {
    2674       45398 :     PLpgSQL_expr *expr = palloc0_object(PLpgSQL_expr);
    2675             : 
    2676       45398 :     expr->query = pstrdup(query);
    2677       45398 :     expr->parseMode = parsemode;
    2678       45398 :     expr->func = plpgsql_curr_compile;
    2679       45398 :     expr->ns = plpgsql_ns_top();
    2680             :     /* might get changed later during parsing: */
    2681       45398 :     expr->target_param = -1;
    2682       45398 :     expr->target_is_local = false;
    2683             :     /* other fields are left as zeroes until first execution */
    2684       45398 :     return expr;
    2685             : }
    2686             : 
    2687             : /* Mark a PLpgSQL_expr as being the source of an assignment to target */
    2688             : static void
    2689        8576 : 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        8576 :     if (target->dtype == PLPGSQL_DTYPE_VAR)
    2697             :     {
    2698        6298 :         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        6298 :         expr->target_is_local = true;
    2706             :     }
    2707             :     else
    2708             :     {
    2709        2278 :         expr->target_param = -1; /* should be that already */
    2710        2278 :         expr->target_is_local = false; /* ditto */
    2711             :     }
    2712        8576 : }
    2713             : 
    2714             : /* Convenience routine to read an expression with one possible terminator */
    2715             : static PLpgSQL_expr *
    2716       12026 : read_sql_expression(int until, const char *expected, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
    2717             : {
    2718       12026 :     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        1586 : read_sql_expression2(int until, int until2, const char *expected,
    2727             :                      int *endtoken, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
    2728             : {
    2729        1586 :     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         348 : read_sql_stmt(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
    2738             : {
    2739         348 :     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       41264 : 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       41264 :     int         startlocation = -1;
    2776       41264 :     int         endlocation = -1;
    2777       41264 :     int         parenlevel = 0;
    2778             :     PLpgSQL_expr *expr;
    2779             : 
    2780       41264 :     initStringInfo(&ds);
    2781             : 
    2782             :     /* special lookup mode for identifiers within the SQL text */
    2783       41264 :     save_IdentifierLookup = plpgsql_IdentifierLookup;
    2784       41264 :     plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
    2785             : 
    2786             :     for (;;)
    2787             :     {
    2788      171908 :         tok = yylex(yylvalp, yyllocp, yyscanner);
    2789      171908 :         if (startlocation < 0)   /* remember loc of first token */
    2790       41264 :             startlocation = *yyllocp;
    2791      171908 :         if (tok == until && parenlevel == 0)
    2792       33806 :             break;
    2793      138102 :         if (tok == until2 && parenlevel == 0)
    2794        6882 :             break;
    2795      131220 :         if (tok == until3 && parenlevel == 0)
    2796         576 :             break;
    2797      130644 :         if (tok == '(' || tok == '[')
    2798       10066 :             parenlevel++;
    2799      120578 :         else if (tok == ')' || tok == ']')
    2800             :         {
    2801       10066 :             parenlevel--;
    2802       10066 :             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      130644 :         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      130644 :         endlocation = *yyllocp + plpgsql_token_length(yyscanner);
    2830             :     }
    2831             : 
    2832       41264 :     plpgsql_IdentifierLookup = save_IdentifierLookup;
    2833             : 
    2834       41264 :     if (startloc)
    2835        2594 :         *startloc = startlocation;
    2836       41264 :     if (endtoken)
    2837       19706 :         *endtoken = tok;
    2838             : 
    2839             :     /* give helpful complaint about empty input */
    2840       41264 :     if (startlocation >= endlocation)
    2841             :     {
    2842           6 :         if (isexpression)
    2843           6 :             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       41258 :     plpgsql_append_source_text(&ds, startlocation, endlocation, yyscanner);
    2856             : 
    2857       41258 :     expr = make_plpgsql_expr(ds.data, parsemode);
    2858       41258 :     pfree(ds.data);
    2859             : 
    2860       41258 :     if (valid_sql)
    2861       38664 :         check_sql_expr(expr->query, expr->parseMode, startlocation, yyscanner);
    2862             : 
    2863       41258 :     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        6092 : read_datatype(int tok, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
    2872             : {
    2873             :     StringInfoData ds;
    2874             :     char       *type_name;
    2875             :     int         startlocation;
    2876        6092 :     PLpgSQL_type *result = NULL;
    2877        6092 :     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        6092 :     if (tok == YYEMPTY)
    2884         172 :         tok = yylex(yylvalp, yyllocp, yyscanner);
    2885             : 
    2886             :     /* The current token is the start of what we'll pass to parse_datatype */
    2887        6092 :     startlocation = *yyllocp;
    2888             : 
    2889             :     /*
    2890             :      * If we have a simple or composite identifier, check for %TYPE and
    2891             :      * %ROWTYPE constructs.
    2892             :      */
    2893        6092 :     if (tok == T_WORD)
    2894             :     {
    2895        6016 :         char       *dtname = yylvalp->word.ident;
    2896             : 
    2897        6016 :         tok = yylex(yylvalp, yyllocp, yyscanner);
    2898        6016 :         if (tok == '%')
    2899             :         {
    2900         104 :             tok = yylex(yylvalp, yyllocp, yyscanner);
    2901         104 :             if (tok_is_keyword(tok, yylvalp,
    2902             :                                K_TYPE, "type"))
    2903          46 :                 result = plpgsql_parse_wordtype(dtname);
    2904          58 :             else if (tok_is_keyword(tok, yylvalp,
    2905             :                                     K_ROWTYPE, "rowtype"))
    2906          58 :                 result = plpgsql_parse_wordrowtype(dtname);
    2907             :         }
    2908             :     }
    2909          76 :     else if (plpgsql_token_is_unreserved_keyword(tok))
    2910             :     {
    2911           4 :         char       *dtname = pstrdup(yylvalp->keyword);
    2912             : 
    2913           4 :         tok = yylex(yylvalp, yyllocp, yyscanner);
    2914           4 :         if (tok == '%')
    2915             :         {
    2916           4 :             tok = yylex(yylvalp, yyllocp, yyscanner);
    2917           4 :             if (tok_is_keyword(tok, yylvalp,
    2918             :                                K_TYPE, "type"))
    2919           2 :                 result = plpgsql_parse_wordtype(dtname);
    2920           2 :             else if (tok_is_keyword(tok, yylvalp,
    2921             :                                     K_ROWTYPE, "rowtype"))
    2922           2 :                 result = plpgsql_parse_wordrowtype(dtname);
    2923             :         }
    2924             :     }
    2925          72 :     else if (tok == T_CWORD)
    2926             :     {
    2927          72 :         List       *dtnames = yylvalp->cword.idents;
    2928             : 
    2929          72 :         tok = yylex(yylvalp, yyllocp, yyscanner);
    2930          72 :         if (tok == '%')
    2931             :         {
    2932          52 :             tok = yylex(yylvalp, yyllocp, yyscanner);
    2933          52 :             if (tok_is_keyword(tok, yylvalp,
    2934             :                                K_TYPE, "type"))
    2935          36 :                 result = plpgsql_parse_cwordtype(dtnames);
    2936          16 :             else if (tok_is_keyword(tok, yylvalp,
    2937             :                                     K_ROWTYPE, "rowtype"))
    2938          16 :                 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        6070 :     if (result)
    2951             :     {
    2952         138 :         bool        is_array = false;
    2953             : 
    2954         138 :         tok = yylex(yylvalp, yyllocp, yyscanner);
    2955         138 :         if (tok_is_keyword(tok, yylvalp,
    2956             :                            K_ARRAY, "array"))
    2957             :         {
    2958           8 :             is_array = true;
    2959           8 :             tok = yylex(yylvalp, yyllocp, yyscanner);
    2960             :         }
    2961         170 :         while (tok == '[')
    2962             :         {
    2963          32 :             is_array = true;
    2964          32 :             tok = yylex(yylvalp, yyllocp, yyscanner);
    2965          32 :             if (tok == ICONST)
    2966          12 :                 tok = yylex(yylvalp, yyllocp, yyscanner);
    2967          32 :             if (tok != ']')
    2968           0 :                 yyerror(yyllocp, NULL, yyscanner, "syntax error, expected \"]\"");
    2969          32 :             tok = yylex(yylvalp, yyllocp, yyscanner);
    2970             :         }
    2971         138 :         plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
    2972             : 
    2973         138 :         if (is_array)
    2974          28 :             result = plpgsql_build_datatype_arrayof(result);
    2975             : 
    2976         136 :         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        6846 :     while (tok != ';')
    2986             :     {
    2987        1876 :         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        1876 :         if (tok == K_COLLATE || tok == K_NOT ||
    2996        1690 :             tok == '=' || tok == COLON_EQUALS || tok == K_DEFAULT)
    2997             :             break;
    2998             :         /* Possible followers for datatype in a cursor_arg list */
    2999        1058 :         if ((tok == ',' || tok == ')') && parenlevel == 0)
    3000         144 :             break;
    3001         914 :         if (tok == '(')
    3002         114 :             parenlevel++;
    3003         800 :         else if (tok == ')')
    3004         114 :             parenlevel--;
    3005             : 
    3006         914 :         tok = yylex(yylvalp, yyllocp, yyscanner);
    3007             :     }
    3008             : 
    3009             :     /* set up ds to contain complete typename text */
    3010        5932 :     initStringInfo(&ds);
    3011        5932 :     plpgsql_append_source_text(&ds, startlocation, *yyllocp, yyscanner);
    3012        5932 :     type_name = ds.data;
    3013             : 
    3014        5932 :     if (type_name[0] == '\0')
    3015           0 :         yyerror(yyllocp, NULL, yyscanner, "missing data type declaration");
    3016             : 
    3017        5932 :     result = parse_datatype(type_name, startlocation, yyscanner);
    3018             : 
    3019        5930 :     pfree(ds.data);
    3020             : 
    3021        5930 :     plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
    3022             : 
    3023        5930 :     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        4092 : 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        4092 :     PLpgSQL_variable *target = NULL;
    3039             :     int         tok;
    3040             :     int         prev_tok;
    3041        4092 :     bool        have_into = false;
    3042        4092 :     bool        have_strict = false;
    3043        4092 :     int         into_start_loc = -1;
    3044        4092 :     int         into_end_loc = -1;
    3045        4092 :     int         paren_depth = 0;
    3046        4092 :     int         begin_depth = 0;
    3047        4092 :     bool        in_routine_definition = false;
    3048        4092 :     int         token_count = 0;
    3049             :     char        tokens[4];      /* records the first few tokens */
    3050             : 
    3051        4092 :     initStringInfo(&ds);
    3052             : 
    3053        4092 :     memset(tokens, 0, sizeof(tokens));
    3054             : 
    3055             :     /* special lookup mode for identifiers within the SQL text */
    3056        4092 :     save_IdentifierLookup = plpgsql_IdentifierLookup;
    3057        4092 :     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        4092 :     tok = firsttoken;
    3094        4092 :     if (tok == T_WORD && strcmp(word->ident, "create") == 0)
    3095          86 :         tokens[token_count] = 'c';
    3096        4092 :     token_count++;
    3097             : 
    3098             :     for (;;)
    3099             :     {
    3100       48550 :         prev_tok = tok;
    3101       48550 :         tok = yylex(yylvalp, yyllocp, yyscanner);
    3102       48550 :         if (have_into && into_end_loc < 0)
    3103        1122 :             into_end_loc = *yyllocp;    /* token after the INTO part */
    3104             :         /* Detect CREATE [OR REPLACE] {FUNCTION|PROCEDURE} */
    3105       48550 :         if (tokens[0] == 'c' && token_count < sizeof(tokens))
    3106             :         {
    3107         258 :             if (tok == K_OR)
    3108           4 :                 tokens[token_count] = 'o';
    3109         254 :             else if (tok == T_WORD &&
    3110         198 :                      strcmp(yylvalp->word.ident, "replace") == 0)
    3111           4 :                 tokens[token_count] = 'r';
    3112         250 :             else if (tok == T_WORD &&
    3113         194 :                      strcmp(yylvalp->word.ident, "function") == 0)
    3114           6 :                 tokens[token_count] = 'f';
    3115         244 :             else if (tok == T_WORD &&
    3116         188 :                      strcmp(yylvalp->word.ident, "procedure") == 0)
    3117           2 :                 tokens[token_count] = 'f';  /* treat same as "function" */
    3118         258 :             if (tokens[1] == 'f' ||
    3119         246 :                 (tokens[1] == 'o' && tokens[2] == 'r' && tokens[3] == 'f'))
    3120          16 :                 in_routine_definition = true;
    3121         258 :             token_count++;
    3122             :         }
    3123             :         /* Track paren nesting (needed for CREATE RULE syntax) */
    3124       48550 :         if (tok == '(')
    3125        2310 :             paren_depth++;
    3126       46240 :         else if (tok == ')' && paren_depth > 0)
    3127        2310 :             paren_depth--;
    3128             :         /* We need track BEGIN/END nesting only in a routine definition */
    3129       48550 :         if (in_routine_definition && paren_depth == 0)
    3130             :         {
    3131          92 :             if (tok == K_BEGIN || tok == K_CASE)
    3132           4 :                 begin_depth++;
    3133          88 :             else if (tok == K_END && begin_depth > 0)
    3134           4 :                 begin_depth--;
    3135             :         }
    3136             :         /* Command-ending semicolon? */
    3137       48550 :         if (tok == ';' && paren_depth == 0 && begin_depth == 0)
    3138        4092 :             break;
    3139       44458 :         if (tok == 0)
    3140           0 :             yyerror(yyllocp, NULL, yyscanner, "unexpected end of function definition");
    3141       44458 :         if (tok == K_INTO)
    3142             :         {
    3143        2094 :             if (prev_tok == K_INSERT)
    3144         918 :                 continue;       /* INSERT INTO is not an INTO-target */
    3145        1176 :             if (prev_tok == K_MERGE)
    3146          54 :                 continue;       /* MERGE INTO is not an INTO-target */
    3147        1122 :             if (firsttoken == K_IMPORT)
    3148           0 :                 continue;       /* IMPORT ... INTO is not an INTO-target */
    3149        1122 :             if (have_into)
    3150           0 :                 yyerror(yyllocp, NULL, yyscanner, "INTO specified more than once");
    3151        1122 :             have_into = true;
    3152        1122 :             into_start_loc = *yyllocp;
    3153        1122 :             plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
    3154        1122 :             read_into_target(&target, &have_strict, yylvalp, yyllocp, yyscanner);
    3155        1122 :             plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
    3156             :         }
    3157             :     }
    3158             : 
    3159        4092 :     plpgsql_IdentifierLookup = save_IdentifierLookup;
    3160             : 
    3161        4092 :     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        1122 :         plpgsql_append_source_text(&ds, location, into_start_loc, yyscanner);
    3169        1122 :         appendStringInfoSpaces(&ds, into_end_loc - into_start_loc);
    3170        1122 :         plpgsql_append_source_text(&ds, into_end_loc, *yyllocp, yyscanner);
    3171             :     }
    3172             :     else
    3173        2970 :         plpgsql_append_source_text(&ds, location, *yyllocp, yyscanner);
    3174             : 
    3175             :     /* trim any trailing whitespace, for neatness */
    3176        7844 :     while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1]))
    3177        3752 :         ds.data[--ds.len] = '\0';
    3178             : 
    3179        4092 :     expr = make_plpgsql_expr(ds.data, RAW_PARSE_DEFAULT);
    3180        4092 :     pfree(ds.data);
    3181             : 
    3182        4092 :     check_sql_expr(expr->query, expr->parseMode, location, yyscanner);
    3183             : 
    3184        4086 :     execsql = palloc0_object(PLpgSQL_stmt_execsql);
    3185        4086 :     execsql->cmd_type = PLPGSQL_STMT_EXECSQL;
    3186        4086 :     execsql->lineno = plpgsql_location_to_lineno(location, yyscanner);
    3187        4086 :     execsql->stmtid = ++plpgsql_curr_compile->nstatements;
    3188        4086 :     execsql->sqlstmt = expr;
    3189        4086 :     execsql->into = have_into;
    3190        4086 :     execsql->strict = have_strict;
    3191        4086 :     execsql->target = target;
    3192             : 
    3193        4086 :     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         140 : read_fetch_direction(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
    3202             : {
    3203             :     PLpgSQL_stmt_fetch *fetch;
    3204             :     int         tok;
    3205         140 :     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         140 :     fetch = (PLpgSQL_stmt_fetch *) palloc0_object(PLpgSQL_stmt_fetch);
    3212         140 :     fetch->cmd_type = PLPGSQL_STMT_FETCH;
    3213         140 :     fetch->stmtid = ++plpgsql_curr_compile->nstatements;
    3214             :     /* set direction defaults: */
    3215         140 :     fetch->direction = FETCH_FORWARD;
    3216         140 :     fetch->how_many = 1;
    3217         140 :     fetch->expr = NULL;
    3218         140 :     fetch->returns_multiple_rows = false;
    3219             : 
    3220         140 :     tok = yylex(yylvalp, yyllocp, yyscanner);
    3221         140 :     if (tok == 0)
    3222           0 :         yyerror(yyllocp, NULL, yyscanner, "unexpected end of function definition");
    3223             : 
    3224         140 :     if (tok_is_keyword(tok, yylvalp,
    3225             :                        K_NEXT, "next"))
    3226             :     {
    3227             :         /* use defaults */
    3228             :     }
    3229         128 :     else if (tok_is_keyword(tok, yylvalp,
    3230             :                             K_PRIOR, "prior"))
    3231             :     {
    3232          18 :         fetch->direction = FETCH_BACKWARD;
    3233             :     }
    3234         110 :     else if (tok_is_keyword(tok, yylvalp,
    3235             :                             K_FIRST, "first"))
    3236             :     {
    3237           0 :         fetch->direction = FETCH_ABSOLUTE;
    3238             :     }
    3239         110 :     else if (tok_is_keyword(tok, yylvalp,
    3240             :                             K_LAST, "last"))
    3241             :     {
    3242          30 :         fetch->direction = FETCH_ABSOLUTE;
    3243          30 :         fetch->how_many = -1;
    3244             :     }
    3245          80 :     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          80 :     else if (tok_is_keyword(tok, yylvalp,
    3255             :                             K_RELATIVE, "relative"))
    3256             :     {
    3257          18 :         fetch->direction = FETCH_RELATIVE;
    3258          18 :         fetch->expr = read_sql_expression2(K_FROM, K_IN,
    3259             :                                            "FROM or IN",
    3260             :                                            NULL, yylvalp, yyllocp, yyscanner);
    3261          18 :         check_FROM = false;
    3262             :     }
    3263          62 :     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          62 :     else if (tok_is_keyword(tok, yylvalp,
    3270             :                             K_FORWARD, "forward"))
    3271             :     {
    3272           6 :         complete_direction(fetch, &check_FROM, yylvalp, yyllocp, yyscanner);
    3273             :     }
    3274          56 :     else if (tok_is_keyword(tok, yylvalp,
    3275             :                             K_BACKWARD, "backward"))
    3276             :     {
    3277          12 :         fetch->direction = FETCH_BACKWARD;
    3278          12 :         complete_direction(fetch, &check_FROM, yylvalp, yyllocp, yyscanner);
    3279             :     }
    3280          44 :     else if (tok == K_FROM || tok == K_IN)
    3281             :     {
    3282             :         /* empty direction */
    3283           0 :         check_FROM = false;
    3284             :     }
    3285          44 :     else if (tok == T_DATUM)
    3286             :     {
    3287             :         /* Assume there's no direction clause and tok is a cursor name */
    3288          44 :         plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
    3289          44 :         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         140 :     if (check_FROM)
    3311             :     {
    3312          66 :         tok = yylex(yylvalp, yyllocp, yyscanner);
    3313          66 :         if (tok != K_FROM && tok != K_IN)
    3314           0 :             yyerror(yyllocp, NULL, yyscanner, "expected FROM or IN");
    3315             :     }
    3316             : 
    3317         140 :     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          18 : complete_direction(PLpgSQL_stmt_fetch *fetch, bool *check_FROM, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
    3328             : {
    3329             :     int         tok;
    3330             : 
    3331          18 :     tok = yylex(yylvalp, yyllocp, yyscanner);
    3332          18 :     if (tok == 0)
    3333           0 :         yyerror(yyllocp, NULL, yyscanner, "unexpected end of function definition");
    3334             : 
    3335          18 :     if (tok == K_FROM || tok == K_IN)
    3336             :     {
    3337           6 :         *check_FROM = false;
    3338           6 :         return;
    3339             :     }
    3340             : 
    3341          12 :     if (tok == K_ALL)
    3342             :     {
    3343           6 :         fetch->how_many = FETCH_ALL;
    3344           6 :         fetch->returns_multiple_rows = true;
    3345           6 :         *check_FROM = true;
    3346           6 :         return;
    3347             :     }
    3348             : 
    3349           6 :     plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
    3350           6 :     fetch->expr = read_sql_expression2(K_FROM, K_IN,
    3351             :                                        "FROM or IN",
    3352             :                                        NULL, yylvalp, yyllocp, yyscanner);
    3353           6 :     fetch->returns_multiple_rows = true;
    3354           6 :     *check_FROM = false;
    3355             : }
    3356             : 
    3357             : 
    3358             : static PLpgSQL_stmt *
    3359        8686 : make_return_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
    3360             : {
    3361             :     PLpgSQL_stmt_return *new;
    3362             : 
    3363        8686 :     new = palloc0_object(PLpgSQL_stmt_return);
    3364        8686 :     new->cmd_type = PLPGSQL_STMT_RETURN;
    3365        8686 :     new->lineno = plpgsql_location_to_lineno(location, yyscanner);
    3366        8686 :     new->stmtid = ++plpgsql_curr_compile->nstatements;
    3367        8686 :     new->expr = NULL;
    3368        8686 :     new->retvarno = -1;
    3369             : 
    3370        8686 :     if (plpgsql_curr_compile->fn_retset)
    3371             :     {
    3372          36 :         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        8650 :     else if (plpgsql_curr_compile->fn_rettype == VOIDOID)
    3380             :     {
    3381         108 :         if (yylex(yylvalp, yyllocp, yyscanner) != ';')
    3382             :         {
    3383          14 :             if (plpgsql_curr_compile->fn_prokind == PROKIND_PROCEDURE)
    3384           2 :                 ereport(ERROR,
    3385             :                         (errcode(ERRCODE_SYNTAX_ERROR),
    3386             :                          errmsg("RETURN cannot have a parameter in a procedure"),
    3387             :                          parser_errposition(*yyllocp)));
    3388             :             else
    3389          12 :                 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        8542 :     else if (plpgsql_curr_compile->out_param_varno >= 0)
    3396             :     {
    3397          54 :         if (yylex(yylvalp, yyllocp, yyscanner) != ';')
    3398           6 :             ereport(ERROR,
    3399             :                     (errcode(ERRCODE_DATATYPE_MISMATCH),
    3400             :                      errmsg("RETURN cannot have a parameter in function with OUT parameters"),
    3401             :                      parser_errposition(*yyllocp)));
    3402          48 :         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        8488 :         int         tok = yylex(yylvalp, yyllocp, yyscanner);
    3411             : 
    3412        8488 :         if (tok == T_DATUM && plpgsql_peek(yyscanner) == ';' &&
    3413        4910 :             (yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_VAR ||
    3414        3850 :              yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_PROMISE ||
    3415        3850 :              yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
    3416        3850 :              yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_REC))
    3417             :         {
    3418        4838 :             new->retvarno = yylvalp->wdatum.datum->dno;
    3419             :             /* eat the semicolon token that we only peeked at above */
    3420        4838 :             tok = yylex(yylvalp, yyllocp, yyscanner);
    3421        4838 :             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        3650 :             plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
    3432        3650 :             new->expr = read_sql_expression(';', ";", yylvalp, yyllocp, yyscanner);
    3433             :         }
    3434             :     }
    3435             : 
    3436        8660 :     return (PLpgSQL_stmt *) new;
    3437             : }
    3438             : 
    3439             : 
    3440             : static PLpgSQL_stmt *
    3441         354 : make_return_next_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
    3442             : {
    3443             :     PLpgSQL_stmt_return_next *new;
    3444             : 
    3445         354 :     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         354 :     new = palloc0_object(PLpgSQL_stmt_return_next);
    3452         354 :     new->cmd_type = PLPGSQL_STMT_RETURN_NEXT;
    3453         354 :     new->lineno = plpgsql_location_to_lineno(location, yyscanner);
    3454         354 :     new->stmtid = ++plpgsql_curr_compile->nstatements;
    3455         354 :     new->expr = NULL;
    3456         354 :     new->retvarno = -1;
    3457             : 
    3458         354 :     if (plpgsql_curr_compile->out_param_varno >= 0)
    3459             :     {
    3460          72 :         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          72 :         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         282 :         int         tok = yylex(yylvalp, yyllocp, yyscanner);
    3474             : 
    3475         282 :         if (tok == T_DATUM && plpgsql_peek(yyscanner) == ';' &&
    3476         246 :             (yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_VAR ||
    3477          68 :              yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_PROMISE ||
    3478          68 :              yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
    3479          68 :              yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_REC))
    3480             :         {
    3481         246 :             new->retvarno = yylvalp->wdatum.datum->dno;
    3482             :             /* eat the semicolon token that we only peeked at above */
    3483         246 :             tok = yylex(yylvalp, yyllocp, yyscanner);
    3484         246 :             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          36 :             plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
    3495          36 :             new->expr = read_sql_expression(';', ";", yylvalp, yyllocp, yyscanner);
    3496             :         }
    3497             :     }
    3498             : 
    3499         354 :     return (PLpgSQL_stmt *) new;
    3500             : }
    3501             : 
    3502             : 
    3503             : static PLpgSQL_stmt *
    3504         176 : 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         176 :     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         176 :     new = palloc0_object(PLpgSQL_stmt_return_query);
    3516         176 :     new->cmd_type = PLPGSQL_STMT_RETURN_QUERY;
    3517         176 :     new->lineno = plpgsql_location_to_lineno(location, yyscanner);
    3518         176 :     new->stmtid = ++plpgsql_curr_compile->nstatements;
    3519             : 
    3520             :     /* check for RETURN QUERY EXECUTE */
    3521         176 :     tok = yylex(yylvalp, yyllocp, yyscanner);
    3522         176 :     if (!tok_is_keyword(tok, yylvalp, K_EXECUTE, "execute"))
    3523             :     {
    3524             :         /* ordinary static query */
    3525          80 :         plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
    3526          80 :         new->query = read_sql_stmt(yylvalp, yyllocp, yyscanner);
    3527             :     }
    3528             :     else
    3529             :     {
    3530             :         /* dynamic SQL */
    3531             :         int         term;
    3532             : 
    3533          96 :         new->dynquery = read_sql_expression2(';', K_USING, "; or USING",
    3534             :                                              &term, yylvalp, yyllocp, yyscanner);
    3535          96 :         if (term == K_USING)
    3536             :         {
    3537             :             do
    3538             :             {
    3539             :                 PLpgSQL_expr *expr;
    3540             : 
    3541          18 :                 expr = read_sql_expression2(',', ';', ", or ;", &term, yylvalp, yyllocp, yyscanner);
    3542          18 :                 new->params = lappend(new->params, expr);
    3543          18 :             } while (term == ',');
    3544             :         }
    3545             :     }
    3546             : 
    3547         176 :     return (PLpgSQL_stmt *) new;
    3548             : }
    3549             : 
    3550             : 
    3551             : /* convenience routine to fetch the name of a T_DATUM */
    3552             : static char *
    3553        1958 : NameOfDatum(PLwdatum *wdatum)
    3554             : {
    3555        1958 :     if (wdatum->ident)
    3556        1866 :         return wdatum->ident;
    3557             :     Assert(wdatum->idents != NIL);
    3558          92 :     return NameListToString(wdatum->idents);
    3559             : }
    3560             : 
    3561             : static void
    3562       11528 : check_assignable(PLpgSQL_datum *datum, int location, yyscan_t yyscanner)
    3563             : {
    3564       11528 :     switch (datum->dtype)
    3565             :     {
    3566       10736 :         case PLPGSQL_DTYPE_VAR:
    3567             :         case PLPGSQL_DTYPE_PROMISE:
    3568             :         case PLPGSQL_DTYPE_REC:
    3569       10736 :             if (((PLpgSQL_variable *) datum)->isconst)
    3570          10 :                 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       10726 :             break;
    3576          16 :         case PLPGSQL_DTYPE_ROW:
    3577             :             /* always assignable; member vars were checked at compile time */
    3578          16 :             break;
    3579         776 :         case PLPGSQL_DTYPE_RECFIELD:
    3580             :             /* assignable if parent record is */
    3581         776 :             check_assignable(plpgsql_Datums[((PLpgSQL_recfield *) datum)->recparentno],
    3582             :                              location, yyscanner);
    3583         772 :             break;
    3584           0 :         default:
    3585           0 :             elog(ERROR, "unrecognized dtype: %d", datum->dtype);
    3586             :             break;
    3587             :     }
    3588       11514 : }
    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        1818 : 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        1818 :     *target = NULL;
    3601        1818 :     if (strict)
    3602        1696 :         *strict = false;
    3603             : 
    3604        1818 :     tok = yylex(yylvalp, yyllocp, yyscanner);
    3605        1818 :     if (strict && tok_is_keyword(tok, yylvalp, K_STRICT, "strict"))
    3606             :     {
    3607         144 :         *strict = true;
    3608         144 :         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        1818 :     switch (tok)
    3619             :     {
    3620        1818 :         case T_DATUM:
    3621        1818 :             if (yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
    3622        1818 :                 yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_REC)
    3623             :             {
    3624         836 :                 check_assignable(yylvalp->wdatum.datum, *yyllocp, yyscanner);
    3625         836 :                 *target = (PLpgSQL_variable *) yylvalp->wdatum.datum;
    3626             : 
    3627         836 :                 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         836 :                 plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
    3633             :             }
    3634             :             else
    3635             :             {
    3636         982 :                 *target = (PLpgSQL_variable *)
    3637         982 :                     read_into_scalar_list(NameOfDatum(&(yylvalp->wdatum)),
    3638             :                                           yylvalp->wdatum.datum, *yyllocp, yylvalp, yyllocp, yyscanner);
    3639             :             }
    3640        1818 :             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        1818 : }
    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        1002 : 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        1002 :     check_assignable(initial_datum, initial_location, yyscanner);
    3668         998 :     fieldnames[0] = initial_name;
    3669         998 :     varnos[0] = initial_datum->dno;
    3670         998 :     nfields = 1;
    3671             : 
    3672        1174 :     while ((tok = yylex(yylvalp, yyllocp, yyscanner)) == ',')
    3673             :     {
    3674             :         /* Check for array overflow */
    3675         176 :         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         176 :         tok = yylex(yylvalp, yyllocp, yyscanner);
    3682         176 :         switch (tok)
    3683             :         {
    3684         176 :             case T_DATUM:
    3685         176 :                 check_assignable(yylvalp->wdatum.datum, *yyllocp, yyscanner);
    3686         176 :                 if (yylvalp->wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
    3687         176 :                     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         176 :                 fieldnames[nfields] = NameOfDatum(&(yylvalp->wdatum));
    3694         176 :                 varnos[nfields++] = yylvalp->wdatum.datum->dno;
    3695         176 :                 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         998 :     plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
    3708             : 
    3709         998 :     row = palloc0_object(PLpgSQL_row);
    3710         998 :     row->dtype = PLPGSQL_DTYPE_ROW;
    3711         998 :     row->refname = "(unnamed row)";
    3712         998 :     row->lineno = plpgsql_location_to_lineno(initial_location, yyscanner);
    3713         998 :     row->rowtupdesc = NULL;
    3714         998 :     row->nfields = nfields;
    3715         998 :     row->fieldnames = palloc_array(char *, nfields);
    3716         998 :     row->varnos = palloc_array(int, nfields);
    3717        2172 :     while (--nfields >= 0)
    3718             :     {
    3719        1174 :         row->fieldnames[nfields] = fieldnames[nfields];
    3720        1174 :         row->varnos[nfields] = varnos[nfields];
    3721             :     }
    3722             : 
    3723         998 :     plpgsql_adddatum((PLpgSQL_datum *) row);
    3724             : 
    3725         998 :     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         378 : 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         378 :     check_assignable(initial_datum, location, yyscanner);
    3743             : 
    3744         378 :     row = palloc0_object(PLpgSQL_row);
    3745         378 :     row->dtype = PLPGSQL_DTYPE_ROW;
    3746         378 :     row->refname = "(unnamed row)";
    3747         378 :     row->lineno = lineno;
    3748         378 :     row->rowtupdesc = NULL;
    3749         378 :     row->nfields = 1;
    3750         378 :     row->fieldnames = palloc_object(char *);
    3751         378 :     row->varnos = palloc_object(int);
    3752         378 :     row->fieldnames[0] = initial_name;
    3753         378 :     row->varnos[0] = initial_datum->dno;
    3754             : 
    3755         378 :     plpgsql_adddatum((PLpgSQL_datum *) row);
    3756             : 
    3757         378 :     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       45350 : 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       45350 :     if (!plpgsql_check_syntax)
    3790       23862 :         return;
    3791             : 
    3792       21488 :     cbarg.location = location;
    3793       21488 :     cbarg.yyscanner = yyscanner;
    3794             : 
    3795       21488 :     syntax_errcontext.callback = plpgsql_sql_error_callback;
    3796       21488 :     syntax_errcontext.arg = &cbarg;
    3797       21488 :     syntax_errcontext.previous = error_context_stack;
    3798       21488 :     error_context_stack = &syntax_errcontext;
    3799             : 
    3800       21488 :     oldCxt = MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
    3801       21488 :     (void) raw_parser(stmt, parseMode);
    3802       21476 :     MemoryContextSwitchTo(oldCxt);
    3803             : 
    3804             :     /* Restore former ereport callback */
    3805       21476 :     error_context_stack = syntax_errcontext.previous;
    3806             : }
    3807             : 
    3808             : static void
    3809          14 : plpgsql_sql_error_callback(void *arg)
    3810             : {
    3811          14 :     sql_error_callback_arg *cbarg = (sql_error_callback_arg *) arg;
    3812          14 :     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          14 :     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          14 :     errpos = geterrposition();
    3827          14 :     if (errpos > 0)
    3828             :     {
    3829          12 :         int         myerrpos = getinternalerrposition();
    3830             : 
    3831          12 :         if (myerrpos > 0)        /* safety check */
    3832          12 :             internalerrposition(myerrpos + errpos - 1);
    3833             :     }
    3834             : 
    3835             :     /* In any case, flush errposition --- we want internalerrposition only */
    3836          14 :     errposition(0);
    3837          14 : }
    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        5932 : 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        5932 :     cbarg.location = location;
    3859        5932 :     cbarg.yyscanner = yyscanner;
    3860             : 
    3861        5932 :     syntax_errcontext.callback = plpgsql_sql_error_callback;
    3862        5932 :     syntax_errcontext.arg = &cbarg;
    3863        5932 :     syntax_errcontext.previous = error_context_stack;
    3864        5932 :     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        5932 :     oldCxt = MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
    3871        5932 :     typeName = typeStringToTypeName(string, NULL);
    3872        5932 :     typenameTypeIdAndMod(NULL, typeName, &type_id, &typmod);
    3873        5930 :     MemoryContextSwitchTo(oldCxt);
    3874             : 
    3875             :     /* Restore former ereport callback */
    3876        5930 :     error_context_stack = syntax_errcontext.previous;
    3877             : 
    3878             :     /* Okay, build a PLpgSQL_type data structure for it */
    3879       11860 :     return plpgsql_build_datatype(type_id, typmod,
    3880        5930 :                                   plpgsql_curr_compile->fn_input_collation,
    3881             :                                   typeName);
    3882             : }
    3883             : 
    3884             : /*
    3885             :  * Check block starting and ending labels match.
    3886             :  */
    3887             : static void
    3888       11560 : check_labels(const char *start_label, const char *end_label, int end_location, yyscan_t yyscanner)
    3889             : {
    3890       11560 :     if (end_label)
    3891             :     {
    3892          10 :         if (!start_label)
    3893           4 :             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           6 :         if (strcmp(start_label, end_label) != 0)
    3900           2 :             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       11554 : }
    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         134 : 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         134 :     bool        any_named = false;
    3928             : 
    3929         134 :     tok = yylex(yylvalp, yyllocp, yyscanner);
    3930         134 :     if (cursor->cursor_explicit_argrow < 0)
    3931             :     {
    3932             :         /* No arguments expected */
    3933          62 :         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          62 :         if (tok != until)
    3941           0 :             yyerror(yyllocp, NULL, yyscanner, "syntax error");
    3942             : 
    3943          62 :         return NULL;
    3944             :     }
    3945             : 
    3946             :     /* Else better provide arguments */
    3947          72 :     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          72 :     row = (PLpgSQL_row *) plpgsql_Datums[cursor->cursor_explicit_argrow];
    3958          72 :     argv = (char **) palloc0_array(char *, row->nfields);
    3959             : 
    3960         192 :     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         144 :         plpgsql_peek2(&tok1, &tok2, &arglocation, NULL, yyscanner);
    3974         144 :         if (tok1 == IDENT && (tok2 == COLON_EQUALS || tok2 == EQUALS_GREATER))
    3975          90 :         {
    3976             :             char       *argname;
    3977             :             IdentifierLookup save_IdentifierLookup;
    3978             : 
    3979             :             /* Read the argument name, ignoring any matching variable */
    3980          90 :             save_IdentifierLookup = plpgsql_IdentifierLookup;
    3981          90 :             plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_DECLARE;
    3982          90 :             yylex(yylvalp, yyllocp, yyscanner);
    3983          90 :             argname = yylvalp->str;
    3984          90 :             plpgsql_IdentifierLookup = save_IdentifierLookup;
    3985             : 
    3986             :             /* Match argument name to cursor arguments */
    3987         150 :             for (argpos = 0; argpos < row->nfields; argpos++)
    3988             :             {
    3989         150 :                 if (strcmp(row->fieldnames[argpos], argname) == 0)
    3990          90 :                     break;
    3991             :             }
    3992          90 :             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          90 :             tok2 = yylex(yylvalp, yyllocp, yyscanner);
    4004          90 :             if (tok2 != COLON_EQUALS && tok2 != EQUALS_GREATER)
    4005           0 :                 yyerror(yyllocp, NULL, yyscanner, "syntax error");
    4006             : 
    4007          90 :             any_named = true;
    4008             :         }
    4009             :         else
    4010          54 :             argpos = argc;
    4011             : 
    4012         144 :         if (argv[argpos] != NULL)
    4013          18 :             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         126 :         item = read_sql_construct(',', ')', 0,
    4026             :                                   ",\" or \")",
    4027             :                                   RAW_PARSE_PLPGSQL_EXPR,
    4028             :                                   true, true,
    4029             :                                   NULL, &endtoken,
    4030             :                                   yylvalp, yyllocp, yyscanner);
    4031             : 
    4032         126 :         argv[argpos] = item->query;
    4033             : 
    4034         126 :         if (endtoken == ')' && !(argc == row->nfields - 1))
    4035           6 :             ereport(ERROR,
    4036             :                     (errcode(ERRCODE_SYNTAX_ERROR),
    4037             :                      errmsg("not enough arguments for cursor \"%s\"",
    4038             :                             cursor->refname),
    4039             :                      parser_errposition(*yyllocp)));
    4040             : 
    4041         120 :         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          48 :     initStringInfo(&ds);
    4051         150 :     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         102 :         appendStringInfoString(&ds, argv[argc]);
    4060         102 :         if (any_named)
    4061          66 :             appendStringInfo(&ds, " AS %s",
    4062          66 :                              quote_identifier(row->fieldnames[argc]));
    4063         102 :         if (argc < row->nfields - 1)
    4064          54 :             appendStringInfoString(&ds, ", ");
    4065             :     }
    4066             : 
    4067          48 :     expr = make_plpgsql_expr(ds.data, RAW_PARSE_PLPGSQL_EXPR);
    4068          48 :     pfree(ds.data);
    4069             : 
    4070             :     /* Next we'd better find the until token */
    4071          48 :     tok = yylex(yylvalp, yyllocp, yyscanner);
    4072          48 :     if (tok != until)
    4073           0 :         yyerror(yyllocp, NULL, yyscanner, "syntax error");
    4074             : 
    4075          48 :     return expr;
    4076             : }
    4077             : 
    4078             : /*
    4079             :  * Parse RAISE ... USING options
    4080             :  */
    4081             : static List *
    4082         180 : read_raise_options(YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_t yyscanner)
    4083             : {
    4084         180 :     List       *result = NIL;
    4085             : 
    4086             :     for (;;)
    4087          96 :     {
    4088             :         PLpgSQL_raise_option *opt;
    4089             :         int         tok;
    4090             : 
    4091         276 :         if ((tok = yylex(yylvalp, yyllocp, yyscanner)) == 0)
    4092           0 :             yyerror(yyllocp, NULL, yyscanner, "unexpected end of function definition");
    4093             : 
    4094         276 :         opt = palloc_object(PLpgSQL_raise_option);
    4095             : 
    4096         276 :         if (tok_is_keyword(tok, yylvalp,
    4097             :                            K_ERRCODE, "errcode"))
    4098          48 :             opt->opt_type = PLPGSQL_RAISEOPTION_ERRCODE;
    4099         228 :         else if (tok_is_keyword(tok, yylvalp,
    4100             :                                 K_MESSAGE, "message"))
    4101         128 :             opt->opt_type = PLPGSQL_RAISEOPTION_MESSAGE;
    4102         100 :         else if (tok_is_keyword(tok, yylvalp,
    4103             :                                 K_DETAIL, "detail"))
    4104          46 :             opt->opt_type = PLPGSQL_RAISEOPTION_DETAIL;
    4105          54 :         else if (tok_is_keyword(tok, yylvalp,
    4106             :                                 K_HINT, "hint"))
    4107          14 :             opt->opt_type = PLPGSQL_RAISEOPTION_HINT;
    4108          40 :         else if (tok_is_keyword(tok, yylvalp,
    4109             :                                 K_COLUMN, "column"))
    4110           8 :             opt->opt_type = PLPGSQL_RAISEOPTION_COLUMN;
    4111          32 :         else if (tok_is_keyword(tok, yylvalp,
    4112             :                                 K_CONSTRAINT, "constraint"))
    4113           8 :             opt->opt_type = PLPGSQL_RAISEOPTION_CONSTRAINT;
    4114          24 :         else if (tok_is_keyword(tok, yylvalp,
    4115             :                                 K_DATATYPE, "datatype"))
    4116           8 :             opt->opt_type = PLPGSQL_RAISEOPTION_DATATYPE;
    4117          16 :         else if (tok_is_keyword(tok, yylvalp,
    4118             :                                 K_TABLE, "table"))
    4119           8 :             opt->opt_type = PLPGSQL_RAISEOPTION_TABLE;
    4120           8 :         else if (tok_is_keyword(tok, yylvalp,
    4121             :                                 K_SCHEMA, "schema"))
    4122           8 :             opt->opt_type = PLPGSQL_RAISEOPTION_SCHEMA;
    4123             :         else
    4124           0 :             yyerror(yyllocp, NULL, yyscanner, "unrecognized RAISE statement option");
    4125             : 
    4126         276 :         tok = yylex(yylvalp, yyllocp, yyscanner);
    4127         276 :         if (tok != '=' && tok != COLON_EQUALS)
    4128           0 :             yyerror(yyllocp, NULL, yyscanner, "syntax error, expected \"=\"");
    4129             : 
    4130         276 :         opt->expr = read_sql_expression2(',', ';', ", or ;", &tok, yylvalp, yyllocp, yyscanner);
    4131             : 
    4132         276 :         result = lappend(result, opt);
    4133             : 
    4134         276 :         if (tok == ';')
    4135         180 :             break;
    4136             :     }
    4137             : 
    4138         180 :     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        7004 : check_raise_parameters(PLpgSQL_stmt_raise *stmt)
    4147             : {
    4148             :     char       *cp;
    4149        7004 :     int         expected_nparams = 0;
    4150             : 
    4151        7004 :     if (stmt->message == NULL)
    4152         208 :         return;
    4153             : 
    4154      143690 :     for (cp = stmt->message; *cp; cp++)
    4155             :     {
    4156      136894 :         if (cp[0] == '%')
    4157             :         {
    4158             :             /* ignore literal % characters */
    4159       14942 :             if (cp[1] == '%')
    4160           6 :                 cp++;
    4161             :             else
    4162       14936 :                 expected_nparams++;
    4163             :         }
    4164             :     }
    4165             : 
    4166        6796 :     if (expected_nparams < list_length(stmt->params))
    4167           6 :         ereport(ERROR,
    4168             :                 (errcode(ERRCODE_SYNTAX_ERROR),
    4169             :                  errmsg("too many parameters specified for RAISE")));
    4170        6790 :     if (expected_nparams > list_length(stmt->params))
    4171           6 :         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          18 : 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          18 :     new = palloc_object(PLpgSQL_stmt_case);
    4186          18 :     new->cmd_type = PLPGSQL_STMT_CASE;
    4187          18 :     new->lineno = plpgsql_location_to_lineno(location, yyscanner);
    4188          18 :     new->stmtid = ++plpgsql_curr_compile->nstatements;
    4189          18 :     new->t_expr = t_expr;
    4190          18 :     new->t_varno = 0;
    4191          18 :     new->case_when_list = case_when_list;
    4192          18 :     new->have_else = (else_stmts != NIL);
    4193             :     /* Get rid of list-with-NULL hack */
    4194          18 :     if (list_length(else_stmts) == 1 && linitial(else_stmts) == NULL)
    4195           0 :         new->else_stmts = NIL;
    4196             :     else
    4197          18 :         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          18 :     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          16 :         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          16 :             plpgsql_build_variable(varname, new->lineno,
    4223             :                                    plpgsql_build_datatype(INT4OID,
    4224             :                                                           -1,
    4225             :                                                           InvalidOid,
    4226             :                                                           NULL),
    4227             :                                    true);
    4228          16 :         new->t_varno = t_var->dno;
    4229             : 
    4230          52 :         foreach(l, case_when_list)
    4231             :         {
    4232          36 :             PLpgSQL_case_when *cwt = (PLpgSQL_case_when *) lfirst(l);
    4233          36 :             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          36 :             initStringInfo(&ds);
    4241             : 
    4242          36 :             appendStringInfo(&ds, "\"%s\" IN (%s)",
    4243             :                              varname, expr->query);
    4244             : 
    4245          36 :             pfree(expr->query);
    4246          36 :             expr->query = pstrdup(ds.data);
    4247             :             /* Adjust expr's namespace to include the case variable */
    4248          36 :             expr->ns = plpgsql_ns_top();
    4249             : 
    4250          36 :             pfree(ds.data);
    4251             :         }
    4252             :     }
    4253             : 
    4254          18 :     return (PLpgSQL_stmt *) new;
    4255             : }

Generated by: LCOV version 1.16