LCOV - code coverage report
Current view: top level - src/pl/plpgsql/src - pl_gram.y (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 1143 1326 86.2 %
Date: 2017-09-29 15:12:54 Functions: 25 28 89.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11