📄 gram.y
字号:
%{/*------------------------------------------------------------------------- * * gram.y - Parser for the PL/pgSQL * procedural language * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.108 2008/01/01 19:46:00 momjian Exp $ * *------------------------------------------------------------------------- */#include "plpgsql.h"#include "parser/parser.h"static PLpgSQL_expr *read_sql_construct(int until, int until2, const char *expected, const char *sqlstart, bool isexpression, bool valid_sql, int *endtoken);static PLpgSQL_expr *read_sql_stmt(const char *sqlstart);static PLpgSQL_type *read_datatype(int tok);static PLpgSQL_stmt *make_execsql_stmt(const char *sqlstart, int lineno);static PLpgSQL_stmt_fetch *read_fetch_direction(void);static PLpgSQL_stmt *make_return_stmt(int lineno);static PLpgSQL_stmt *make_return_next_stmt(int lineno);static PLpgSQL_stmt *make_return_query_stmt(int lineno);static void check_assignable(PLpgSQL_datum *datum);static void read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row, bool *strict);static PLpgSQL_row *read_into_scalar_list(const char *initial_name, PLpgSQL_datum *initial_datum);static PLpgSQL_row *make_scalar_list1(const char *initial_name, PLpgSQL_datum *initial_datum, int lineno);static void check_sql_expr(const char *stmt);static void plpgsql_sql_error_callback(void *arg);static char *check_label(const char *yytxt);static void check_labels(const char *start_label, const char *end_label);%}%name-prefix="plpgsql_yy"%union { int32 ival; bool boolean; char *str; struct { char *name; int lineno; } varname; struct { char *name; int lineno; PLpgSQL_datum *scalar; PLpgSQL_rec *rec; PLpgSQL_row *row; } forvariable; struct { char *label; int n_initvars; int *initvarnos; } declhdr; struct { char *end_label; List *stmts; } loop_body; List *list; PLpgSQL_type *dtype; PLpgSQL_datum *scalar; /* a VAR, RECFIELD, or TRIGARG */ PLpgSQL_variable *variable; /* a VAR, REC, or ROW */ PLpgSQL_var *var; PLpgSQL_row *row; PLpgSQL_rec *rec; PLpgSQL_expr *expr; PLpgSQL_stmt *stmt; PLpgSQL_stmt_block *program; PLpgSQL_condition *condition; PLpgSQL_exception *exception; PLpgSQL_exception_block *exception_block; PLpgSQL_nsitem *nsitem; PLpgSQL_diag_item *diagitem; PLpgSQL_stmt_fetch *fetch;}%type <declhdr> decl_sect%type <varname> decl_varname%type <str> decl_renname%type <boolean> decl_const decl_notnull exit_type%type <expr> decl_defval decl_cursor_query%type <dtype> decl_datatype%type <row> decl_cursor_args%type <list> decl_cursor_arglist%type <nsitem> decl_aliasitem%type <str> decl_stmts decl_stmt%type <expr> expr_until_semi expr_until_rightbracket%type <expr> expr_until_then expr_until_loop%type <expr> opt_exitcond%type <ival> assign_var%type <var> cursor_variable%type <variable> decl_cursor_arg%type <forvariable> for_variable%type <stmt> for_control%type <str> opt_lblname opt_block_label opt_label%type <str> execsql_start%type <list> proc_sect proc_stmts stmt_else%type <loop_body> loop_body%type <stmt> proc_stmt pl_block%type <stmt> stmt_assign stmt_if stmt_loop stmt_while stmt_exit%type <stmt> stmt_return stmt_raise stmt_execsql stmt_execsql_insert%type <stmt> stmt_dynexecute stmt_for stmt_perform stmt_getdiag%type <stmt> stmt_open stmt_fetch stmt_move stmt_close stmt_null%type <list> proc_exceptions%type <exception_block> exception_sect%type <exception> proc_exception%type <condition> proc_conditions%type <ival> raise_level%type <str> raise_msg%type <list> getdiag_list%type <diagitem> getdiag_list_item%type <ival> getdiag_kind getdiag_target%type <ival> opt_scrollable%type <fetch> opt_fetch_direction%type <ival> lno /* * Keyword tokens */%token K_ALIAS%token K_ASSIGN%token K_BEGIN%token K_BY%token K_CLOSE%token K_CONSTANT%token K_CONTINUE%token K_CURSOR%token K_DEBUG%token K_DECLARE%token K_DEFAULT%token K_DIAGNOSTICS%token K_DOTDOT%token K_ELSE%token K_ELSIF%token K_END%token K_EXCEPTION%token K_EXECUTE%token K_EXIT%token K_FOR%token K_FETCH%token K_FROM%token K_GET%token K_IF%token K_IN%token K_INFO%token K_INSERT%token K_INTO%token K_IS%token K_LOG%token K_LOOP%token K_MOVE%token K_NOSCROLL%token K_NOT%token K_NOTICE%token K_NULL%token K_OPEN%token K_OR%token K_PERFORM%token K_ROW_COUNT%token K_RAISE%token K_RENAME%token K_RESULT_OID%token K_RETURN%token K_REVERSE%token K_SCROLL%token K_STRICT%token K_THEN%token K_TO%token K_TYPE%token K_WARNING%token K_WHEN%token K_WHILE /* * Other tokens */%token T_FUNCTION%token T_TRIGGER%token T_STRING%token T_NUMBER%token T_SCALAR /* a VAR, RECFIELD, or TRIGARG */%token T_ROW%token T_RECORD%token T_DTYPE%token T_WORD%token T_ERROR%token O_OPTION%token O_DUMP%%pl_function : T_FUNCTION comp_optsect pl_block opt_semi { yylval.program = (PLpgSQL_stmt_block *)$3; } | T_TRIGGER comp_optsect pl_block opt_semi { yylval.program = (PLpgSQL_stmt_block *)$3; } ;comp_optsect : | comp_options ;comp_options : comp_options comp_option | comp_option ;comp_option : O_OPTION O_DUMP { plpgsql_DumpExecTree = true; } ;opt_semi : | ';' ;pl_block : decl_sect K_BEGIN lno proc_sect exception_sect K_END opt_label { PLpgSQL_stmt_block *new; new = palloc0(sizeof(PLpgSQL_stmt_block)); new->cmd_type = PLPGSQL_STMT_BLOCK; new->lineno = $3; new->label = $1.label; new->n_initvars = $1.n_initvars; new->initvarnos = $1.initvarnos; new->body = $4; new->exceptions = $5; check_labels($1.label, $7); plpgsql_ns_pop(); $$ = (PLpgSQL_stmt *)new; } ;decl_sect : opt_block_label { plpgsql_ns_setlocal(false); $$.label = $1; $$.n_initvars = 0; $$.initvarnos = NULL; } | opt_block_label decl_start { plpgsql_ns_setlocal(false); $$.label = $1; $$.n_initvars = 0; $$.initvarnos = NULL; } | opt_block_label decl_start decl_stmts { plpgsql_ns_setlocal(false); if ($3 != NULL) $$.label = $3; else $$.label = $1; /* Remember variables declared in decl_stmts */ $$.n_initvars = plpgsql_add_initdatums(&($$.initvarnos)); } ;decl_start : K_DECLARE { /* Forget any variables created before block */ plpgsql_add_initdatums(NULL); /* Make variable names be local to block */ plpgsql_ns_setlocal(true); } ;decl_stmts : decl_stmts decl_stmt { $$ = $2; } | decl_stmt { $$ = $1; } ;decl_stmt : '<' '<' opt_lblname '>' '>' { $$ = $3; } | K_DECLARE { $$ = NULL; } | decl_statement { $$ = NULL; } ;decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval { PLpgSQL_variable *var; var = plpgsql_build_variable($1.name, $1.lineno, $3, true); if ($2) { if (var->dtype == PLPGSQL_DTYPE_VAR) ((PLpgSQL_var *) var)->isconst = $2; else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("row or record variable cannot be CONSTANT"))); } if ($4) { if (var->dtype == PLPGSQL_DTYPE_VAR) ((PLpgSQL_var *) var)->notnull = $4; else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("row or record variable cannot be NOT NULL"))); } if ($5 != NULL) { if (var->dtype == PLPGSQL_DTYPE_VAR) ((PLpgSQL_var *) var)->default_val = $5; else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("default value for row or record variable is not supported"))); } } | decl_varname K_ALIAS K_FOR decl_aliasitem ';' { plpgsql_ns_additem($4->itemtype, $4->itemno, $1.name); } | K_RENAME decl_renname K_TO decl_renname ';' { plpgsql_ns_rename($2, $4); } | decl_varname opt_scrollable K_CURSOR { plpgsql_ns_push($1.name); } decl_cursor_args decl_is_for decl_cursor_query { PLpgSQL_var *new; PLpgSQL_expr *curname_def; char buf[1024]; char *cp1; char *cp2; /* pop local namespace for cursor args */ plpgsql_ns_pop(); new = (PLpgSQL_var *) plpgsql_build_variable($1.name, $1.lineno, plpgsql_build_datatype(REFCURSOROID, -1), true); curname_def = palloc0(sizeof(PLpgSQL_expr)); curname_def->dtype = PLPGSQL_DTYPE_EXPR; strcpy(buf, "SELECT "); cp1 = new->refname; cp2 = buf + strlen(buf); /* * Don't trust standard_conforming_strings here; * it might change before we use the string. */ if (strchr(cp1, '\\') != NULL) *cp2++ = ESCAPE_STRING_SYNTAX; *cp2++ = '\''; while (*cp1) { if (SQL_STR_DOUBLE(*cp1, true)) *cp2++ = *cp1; *cp2++ = *cp1++; } strcpy(cp2, "'::refcursor"); curname_def->query = pstrdup(buf); new->default_val = curname_def; new->cursor_explicit_expr = $7; if ($5 == NULL) new->cursor_explicit_argrow = -1; else new->cursor_explicit_argrow = $5->rowno; new->cursor_options = CURSOR_OPT_FAST_PLAN | $2; } ;opt_scrollable : { $$ = 0; } | K_NOSCROLL { $$ = CURSOR_OPT_NO_SCROLL; } | K_SCROLL { $$ = CURSOR_OPT_SCROLL; } ;decl_cursor_query : { PLpgSQL_expr *query; plpgsql_ns_setlocal(false); query = read_sql_stmt(""); plpgsql_ns_setlocal(true); $$ = query; } ;decl_cursor_args : { $$ = NULL; } | '(' decl_cursor_arglist ')' { PLpgSQL_row *new; int i; ListCell *l; new = palloc0(sizeof(PLpgSQL_row)); new->dtype = PLPGSQL_DTYPE_ROW; new->lineno = plpgsql_scanner_lineno(); new->rowtupdesc = NULL; new->nfields = list_length($2); new->fieldnames = palloc(new->nfields * sizeof(char *)); new->varnos = palloc(new->nfields * sizeof(int)); i = 0; foreach (l, $2) { PLpgSQL_variable *arg = (PLpgSQL_variable *) lfirst(l); new->fieldnames[i] = arg->refname; new->varnos[i] = arg->dno; i++; } list_free($2); plpgsql_adddatum((PLpgSQL_datum *) new); $$ = new; } ;decl_cursor_arglist : decl_cursor_arg { $$ = list_make1($1); } | decl_cursor_arglist ',' decl_cursor_arg { $$ = lappend($1, $3); } ;decl_cursor_arg : decl_varname decl_datatype { $$ = plpgsql_build_variable($1.name, $1.lineno, $2, true); } ;decl_is_for : K_IS | /* Oracle */ K_FOR; /* ANSI */decl_aliasitem : T_WORD { char *name; PLpgSQL_nsitem *nsi; plpgsql_convert_ident(yytext, &name, 1); if (name[0] != '$') yyerror("only positional parameters can be aliased"); plpgsql_ns_setlocal(false); nsi = plpgsql_ns_lookup(name, NULL, NULL, NULL); if (nsi == NULL) { plpgsql_error_lineno = plpgsql_scanner_lineno(); ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PARAMETER), errmsg("function has no parameter \"%s\"", name))); } plpgsql_ns_setlocal(true); pfree(name); $$ = nsi; } ;decl_varname : T_WORD { char *name; plpgsql_convert_ident(yytext, &name, 1); $$.name = name; $$.lineno = plpgsql_scanner_lineno(); } ;decl_renname : T_WORD { char *name; plpgsql_convert_ident(yytext, &name, 1); /* the result must be palloc'd, see plpgsql_ns_rename */ $$ = name; } ;decl_const : { $$ = false; } | K_CONSTANT { $$ = true; } ;decl_datatype : { /* * If there's a lookahead token, read_datatype * should consume it. */ $$ = read_datatype(yychar); yyclearin; } ;decl_notnull : { $$ = false; } | K_NOT K_NULL { $$ = true; } ;decl_defval : ';' { $$ = NULL; } | decl_defkey { plpgsql_ns_setlocal(false); $$ = plpgsql_read_expression(';', ";"); plpgsql_ns_setlocal(true); } ;decl_defkey : K_ASSIGN | K_DEFAULT ;proc_sect : { $$ = NIL; } | proc_stmts { $$ = $1; } ;proc_stmts : proc_stmts proc_stmt { if ($2 == NULL) $$ = $1; else $$ = lappend($1, $2); } | proc_stmt { if ($1 == NULL) $$ = NULL; else $$ = list_make1($1); } ;proc_stmt : pl_block ';' { $$ = $1; } | stmt_assign { $$ = $1; } | stmt_if { $$ = $1; } | stmt_loop { $$ = $1; } | stmt_while { $$ = $1; } | stmt_for { $$ = $1; } | stmt_exit { $$ = $1; } | stmt_return { $$ = $1; } | stmt_raise { $$ = $1; } | stmt_execsql { $$ = $1; } | stmt_execsql_insert { $$ = $1; } | stmt_dynexecute { $$ = $1; } | stmt_perform { $$ = $1; } | stmt_getdiag
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -