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

Generated by: LCOV version 1.14