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 : }
|