📄 gram.y
字号:
} ;execsql_start : T_WORD { $$ = strdup(yytext); } | T_ERROR { $$ = strdup(yytext); } ;expr_until_semi : { $$ = plpgsql_read_expression(';', ";"); } ;expr_until_rightbracket : { $$ = plpgsql_read_expression(']', "]"); } ;expr_until_then : { $$ = plpgsql_read_expression(K_THEN, "THEN"); } ;expr_until_loop : { $$ = plpgsql_read_expression(K_LOOP, "LOOP"); } ;opt_label : { plpgsql_ns_push(NULL); $$ = NULL; } | '<' '<' opt_lblname '>' '>' { plpgsql_ns_push($3); $$ = $3; } ;opt_exitlabel : { $$ = NULL; } | T_LABEL { $$ = strdup(yytext); } ;opt_exitcond : ';' { $$ = NULL; } | K_WHEN expr_until_semi { $$ = $2; } ;opt_lblname : T_WORD { char *name; plpgsql_convert_ident(yytext, &name, 1); $$ = strdup(name); pfree(name); } ;lno : { $$ = plpgsql_error_lineno = plpgsql_scanner_lineno(); } ;%%PLpgSQL_expr *plpgsql_read_expression(int until, const char *expected){ return read_sql_construct(until, expected, true, "SELECT ");}static PLpgSQL_expr *read_sql_stmt(const char *sqlstart){ return read_sql_construct(';', ";", false, sqlstart);}static PLpgSQL_expr *read_sql_construct(int until, const char *expected, bool isexpression, const char *sqlstart){ int tok; int lno; PLpgSQL_dstring ds; int parenlevel = 0; int nparams = 0; int params[1024]; char buf[32]; PLpgSQL_expr *expr; lno = plpgsql_scanner_lineno(); plpgsql_dstring_init(&ds); plpgsql_dstring_append(&ds, (char *) sqlstart); for (;;) { tok = yylex(); if (tok == until && parenlevel == 0) break; if (tok == '(' || tok == '[') parenlevel++; else if (tok == ')' || tok == ']') { parenlevel--; if (parenlevel < 0) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("mismatched parentheses"))); } /* * End of function definition is an error, and we don't expect to * hit a semicolon either (unless it's the until symbol, in which * case we should have fallen out above). */ if (tok == 0 || tok == ';') { plpgsql_error_lineno = lno; if (parenlevel != 0) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("mismatched parentheses"))); if (isexpression) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("missing \"%s\" at end of SQL expression", expected))); else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("missing \"%s\" at end of SQL statement", expected))); break; } if (plpgsql_SpaceScanned) plpgsql_dstring_append(&ds, " "); switch (tok) { case T_VARIABLE: params[nparams] = yylval.variable->dno; snprintf(buf, sizeof(buf), " $%d ", ++nparams); plpgsql_dstring_append(&ds, buf); break; default: plpgsql_dstring_append(&ds, yytext); break; } } expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int)); expr->dtype = PLPGSQL_DTYPE_EXPR; expr->query = strdup(plpgsql_dstring_get(&ds)); expr->plan = NULL; expr->nparams = nparams; while(nparams-- > 0) expr->params[nparams] = params[nparams]; plpgsql_dstring_free(&ds); return expr;}static PLpgSQL_type *read_datatype(int tok){ int lno; PLpgSQL_dstring ds; PLpgSQL_type *result; bool needspace = false; int parenlevel = 0; lno = plpgsql_scanner_lineno(); /* Often there will be a lookahead token, but if not, get one */ if (tok == YYEMPTY) tok = yylex(); if (tok == T_DTYPE) { /* lexer found word%TYPE and did its thing already */ return yylval.dtype; } plpgsql_dstring_init(&ds); while (tok != ';') { if (tok == 0) { plpgsql_error_lineno = lno; if (parenlevel != 0) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("mismatched parentheses"))); ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("incomplete datatype declaration"))); } /* Possible followers for datatype in a declaration */ if (tok == K_NOT || tok == K_ASSIGN || tok == K_DEFAULT) break; /* Possible followers for datatype in a cursor_arg list */ if ((tok == ',' || tok == ')') && parenlevel == 0) break; if (tok == '(') parenlevel++; else if (tok == ')') parenlevel--; if (needspace) plpgsql_dstring_append(&ds, " "); needspace = true; plpgsql_dstring_append(&ds, yytext); tok = yylex(); } plpgsql_push_back_token(tok); plpgsql_error_lineno = lno; /* in case of error in parse_datatype */ result = plpgsql_parse_datatype(plpgsql_dstring_get(&ds)); plpgsql_dstring_free(&ds); return result;}static PLpgSQL_stmt *make_select_stmt(void){ PLpgSQL_dstring ds; int nparams = 0; int params[1024]; char buf[32]; PLpgSQL_expr *expr; PLpgSQL_row *row = NULL; PLpgSQL_rec *rec = NULL; int tok = 0; int have_nexttok = 0; int have_into = 0; plpgsql_dstring_init(&ds); plpgsql_dstring_append(&ds, "SELECT "); while(1) { if (!have_nexttok) tok = yylex(); have_nexttok = 0; if (tok == ';') break; if (tok == 0) { plpgsql_error_lineno = plpgsql_scanner_lineno(); ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("unexpected end of function definition"))); } if (tok == K_INTO) { if (have_into) { plpgsql_error_lineno = plpgsql_scanner_lineno(); ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("INTO specified more than once"))); } tok = yylex(); switch (tok) { case T_ROW: row = yylval.row; have_into = 1; break; case T_RECORD: rec = yylval.rec; have_into = 1; break; case T_VARIABLE: { int nfields = 1; char *fieldnames[1024]; int varnos[1024]; check_assignable(yylval.variable); fieldnames[0] = strdup(yytext); varnos[0] = yylval.variable->dno; while ((tok = yylex()) == ',') { tok = yylex(); switch(tok) { case T_VARIABLE: check_assignable(yylval.variable); fieldnames[nfields] = strdup(yytext); varnos[nfields++] = yylval.variable->dno; break; default: plpgsql_error_lineno = plpgsql_scanner_lineno(); ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("\"%s\" is not a variable", yytext))); } } have_nexttok = 1; row = malloc(sizeof(PLpgSQL_row)); row->dtype = PLPGSQL_DTYPE_ROW; row->refname = strdup("*internal*"); row->lineno = plpgsql_scanner_lineno(); row->rowtupdesc = NULL; row->nfields = nfields; row->fieldnames = malloc(sizeof(char *) * nfields); row->varnos = malloc(sizeof(int) * nfields); while (--nfields >= 0) { row->fieldnames[nfields] = fieldnames[nfields]; row->varnos[nfields] = varnos[nfields]; } plpgsql_adddatum((PLpgSQL_datum *)row); have_into = 1; } break; default: /* Treat the INTO as non-special */ plpgsql_dstring_append(&ds, " INTO "); have_nexttok = 1; break; } continue; } if (plpgsql_SpaceScanned) plpgsql_dstring_append(&ds, " "); switch (tok) { case T_VARIABLE: params[nparams] = yylval.variable->dno; snprintf(buf, sizeof(buf), " $%d ", ++nparams); plpgsql_dstring_append(&ds, buf); break; default: plpgsql_dstring_append(&ds, yytext); break; } } expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int)); expr->dtype = PLPGSQL_DTYPE_EXPR; expr->query = strdup(plpgsql_dstring_get(&ds)); expr->plan = NULL; expr->nparams = nparams; while(nparams-- > 0) expr->params[nparams] = params[nparams]; plpgsql_dstring_free(&ds); if (have_into) { PLpgSQL_stmt_select *select; select = malloc(sizeof(PLpgSQL_stmt_select)); memset(select, 0, sizeof(PLpgSQL_stmt_select)); select->cmd_type = PLPGSQL_STMT_SELECT; select->rec = rec; select->row = row; select->query = expr; return (PLpgSQL_stmt *)select; } else { PLpgSQL_stmt_execsql *execsql; execsql = malloc(sizeof(PLpgSQL_stmt_execsql)); execsql->cmd_type = PLPGSQL_STMT_EXECSQL; execsql->sqlstmt = expr; return (PLpgSQL_stmt *)execsql; }}static PLpgSQL_stmt *make_fetch_stmt(void){ int tok; PLpgSQL_row *row = NULL; PLpgSQL_rec *rec = NULL; PLpgSQL_stmt_fetch *fetch; int have_nexttok = 0; /* We have already parsed everything through the INTO keyword */ tok = yylex(); switch (tok) { case T_ROW: row = yylval.row; break; case T_RECORD: rec = yylval.rec; break; case T_VARIABLE: { int nfields = 1; char *fieldnames[1024]; int varnos[1024]; check_assignable(yylval.variable); fieldnames[0] = strdup(yytext); varnos[0] = yylval.variable->dno; while ((tok = yylex()) == ',') { tok = yylex(); switch(tok) { case T_VARIABLE: check_assignable(yylval.variable); fieldnames[nfields] = strdup(yytext); varnos[nfields++] = yylval.variable->dno; break; default: plpgsql_error_lineno = plpgsql_scanner_lineno(); ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("\"%s\" is not a variable", yytext))); } } have_nexttok = 1; row = malloc(sizeof(PLpgSQL_row)); row->dtype = PLPGSQL_DTYPE_ROW; row->refname = strdup("*internal*"); row->lineno = plpgsql_scanner_lineno(); row->rowtupdesc = NULL; row->nfields = nfields; row->fieldnames = malloc(sizeof(char *) * nfields); row->varnos = malloc(sizeof(int) * nfields); while (--nfields >= 0) { row->fieldnames[nfields] = fieldnames[nfields]; row->varnos[nfields] = varnos[nfields]; } plpgsql_adddatum((PLpgSQL_datum *)row); } break; default: yyerror("syntax error"); } if (!have_nexttok) tok = yylex(); if (tok != ';') yyerror("syntax error"); fetch = malloc(sizeof(PLpgSQL_stmt_select)); memset(fetch, 0, sizeof(PLpgSQL_stmt_fetch)); fetch->cmd_type = PLPGSQL_STMT_FETCH; fetch->rec = rec; fetch->row = row; return (PLpgSQL_stmt *)fetch;}static voidcheck_assignable(PLpgSQL_datum *datum){ switch (datum->dtype) { case PLPGSQL_DTYPE_VAR: if (((PLpgSQL_var *) datum)->isconst) { plpgsql_error_lineno = plpgsql_scanner_lineno(); ereport(ERROR, (errcode(ERRCODE_ERROR_IN_ASSIGNMENT), errmsg("\"%s\" is declared CONSTANT", ((PLpgSQL_var *) datum)->refname))); } break; case PLPGSQL_DTYPE_RECFIELD: /* always assignable? */ break; case PLPGSQL_DTYPE_ARRAYELEM: /* always assignable? */ break; case PLPGSQL_DTYPE_TRIGARG: yyerror("cannot assign to tg_argv"); break; default: elog(ERROR, "unrecognized dtype: %d", datum->dtype); break; }}#include "pl_scan.c"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -