⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gram.y

📁 postgresql8.3.4源码,开源数据库
💻 Y
📖 第 1 页 / 共 4 页
字号:
loop_body		: proc_sect K_END K_LOOP opt_label ';'					{						$$.stmts = $1;						$$.end_label = $4;					}				;stmt_execsql	: execsql_start lno					{						$$ = make_execsql_stmt($1, $2);					}				;/* this matches any otherwise-unrecognized starting keyword */execsql_start	: T_WORD					{ $$ = pstrdup(yytext); }				| T_ERROR					{ $$ = pstrdup(yytext); }				;stmt_execsql_insert : K_INSERT lno K_INTO					{						/*						 * We have to special-case INSERT so that its INTO						 * won't be treated as an INTO-variables clause.						 *						 * Fortunately, this is the only valid use of INTO						 * in a pl/pgsql SQL command, and INTO is already						 * a fully reserved word in the main grammar.						 */						$$ = make_execsql_stmt("INSERT INTO", $2);					}				;stmt_dynexecute : K_EXECUTE lno					{						PLpgSQL_stmt_dynexecute *new;						PLpgSQL_expr *expr;						int endtoken;						expr = read_sql_construct(K_INTO, ';', "INTO|;",												  "SELECT ",												  true, true, &endtoken);						new = palloc(sizeof(PLpgSQL_stmt_dynexecute));						new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;						new->lineno = $2;						new->query = expr;						new->into = false;						new->strict = false;						new->rec = NULL;						new->row = NULL;						/* If we found "INTO", collect the argument */						if (endtoken == K_INTO)						{							new->into = true;							read_into_target(&new->rec, &new->row, &new->strict);							if (yylex() != ';')								yyerror("syntax error");						}						$$ = (PLpgSQL_stmt *)new;					}				;stmt_open		: K_OPEN lno cursor_variable					{						PLpgSQL_stmt_open *new;						int				  tok;						new = palloc0(sizeof(PLpgSQL_stmt_open));						new->cmd_type = PLPGSQL_STMT_OPEN;						new->lineno = $2;						new->curvar = $3->varno;						new->cursor_options = CURSOR_OPT_FAST_PLAN;						if ($3->cursor_explicit_expr == NULL)						{							/* be nice if we could use opt_scrollable here */						    tok = yylex();							if (tok == K_NOSCROLL)							{								new->cursor_options |= CURSOR_OPT_NO_SCROLL;								tok = yylex();							}							else if (tok == K_SCROLL)							{								new->cursor_options |= CURSOR_OPT_SCROLL;								tok = yylex();							}							if (tok != K_FOR)							{								plpgsql_error_lineno = $2;								ereport(ERROR,										(errcode(ERRCODE_SYNTAX_ERROR),										 errmsg("syntax error at \"%s\"",												yytext),										 errdetail("Expected FOR to open a reference cursor.")));							}							tok = yylex();							if (tok == K_EXECUTE)							{								new->dynquery = read_sql_stmt("SELECT ");							}							else							{								plpgsql_push_back_token(tok);								new->query = read_sql_stmt("");							}						}						else						{							if ($3->cursor_explicit_argrow >= 0)							{								char   *cp;								tok = yylex();								if (tok != '(')								{									plpgsql_error_lineno = plpgsql_scanner_lineno();									ereport(ERROR,											(errcode(ERRCODE_SYNTAX_ERROR),											 errmsg("cursor \"%s\" has arguments",													$3->refname)));								}								/*								 * Push back the '(', else read_sql_stmt								 * will complain about unbalanced parens.								 */								plpgsql_push_back_token(tok);								new->argquery = read_sql_stmt("SELECT ");								/*								 * Now remove the leading and trailing parens,								 * because we want "select 1, 2", not								 * "select (1, 2)".								 */								cp = new->argquery->query;								if (strncmp(cp, "SELECT", 6) != 0)								{									plpgsql_error_lineno = plpgsql_scanner_lineno();									/* internal error */									elog(ERROR, "expected \"SELECT (\", got \"%s\"",										 new->argquery->query);								}								cp += 6;								while (*cp == ' ') /* could be more than 1 space here */									cp++;								if (*cp != '(')								{									plpgsql_error_lineno = plpgsql_scanner_lineno();									/* internal error */									elog(ERROR, "expected \"SELECT (\", got \"%s\"",										 new->argquery->query);								}								*cp = ' ';								cp += strlen(cp) - 1;								if (*cp != ')')									yyerror("expected \")\"");								*cp = '\0';							}							else							{								tok = yylex();								if (tok == '(')								{									plpgsql_error_lineno = plpgsql_scanner_lineno();									ereport(ERROR,											(errcode(ERRCODE_SYNTAX_ERROR),											 errmsg("cursor \"%s\" has no arguments",													$3->refname)));								}								if (tok != ';')								{									plpgsql_error_lineno = plpgsql_scanner_lineno();									ereport(ERROR,											(errcode(ERRCODE_SYNTAX_ERROR),											 errmsg("syntax error at \"%s\"",													yytext)));								}							}						}						$$ = (PLpgSQL_stmt *)new;					}				;stmt_fetch		: K_FETCH lno opt_fetch_direction cursor_variable K_INTO					{						PLpgSQL_stmt_fetch *fetch = $3;						PLpgSQL_rec	   *rec;						PLpgSQL_row	   *row;						/* We have already parsed everything through the INTO keyword */						read_into_target(&rec, &row, NULL);						if (yylex() != ';')							yyerror("syntax error");						fetch->lineno = $2;						fetch->rec		= rec;						fetch->row		= row;						fetch->curvar	= $4->varno;						fetch->is_move	= false;						$$ = (PLpgSQL_stmt *)fetch;					}				;				stmt_move		: K_MOVE lno opt_fetch_direction cursor_variable ';'					{						PLpgSQL_stmt_fetch *fetch = $3;						fetch->lineno = $2;						fetch->curvar	= $4->varno;						fetch->is_move	= true;						$$ = (PLpgSQL_stmt *)fetch;					}				;opt_fetch_direction	:					{						$$ = read_fetch_direction();					}				;stmt_close		: K_CLOSE lno cursor_variable ';'					{						PLpgSQL_stmt_close *new;						new = palloc(sizeof(PLpgSQL_stmt_close));						new->cmd_type = PLPGSQL_STMT_CLOSE;						new->lineno = $2;						new->curvar = $3->varno;						$$ = (PLpgSQL_stmt *)new;					}				;stmt_null		: K_NULL ';'					{						/* We do not bother building a node for NULL */						$$ = NULL;					}				;cursor_variable	: T_SCALAR					{						if (yylval.scalar->dtype != PLPGSQL_DTYPE_VAR)							yyerror("cursor variable must be a simple variable");						if (((PLpgSQL_var *) yylval.scalar)->datatype->typoid != REFCURSOROID)						{							plpgsql_error_lineno = plpgsql_scanner_lineno();							ereport(ERROR,									(errcode(ERRCODE_DATATYPE_MISMATCH),									 errmsg("\"%s\" must be of type cursor or refcursor",											((PLpgSQL_var *) yylval.scalar)->refname)));						}						$$ = (PLpgSQL_var *) yylval.scalar;					}				;exception_sect	:					{ $$ = NULL; }				| K_EXCEPTION lno					{						/*						 * We use a mid-rule action to add these						 * special variables to the namespace before						 * parsing the WHEN clauses themselves.						 */						PLpgSQL_exception_block *new = palloc(sizeof(PLpgSQL_exception_block));						PLpgSQL_variable *var;						var = plpgsql_build_variable("sqlstate", $2,													 plpgsql_build_datatype(TEXTOID, -1),													 true);						((PLpgSQL_var *) var)->isconst = true;						new->sqlstate_varno = var->dno;						var = plpgsql_build_variable("sqlerrm", $2,													 plpgsql_build_datatype(TEXTOID, -1),													 true);						((PLpgSQL_var *) var)->isconst = true;						new->sqlerrm_varno = var->dno;						$<exception_block>$ = new;					}					proc_exceptions					{						PLpgSQL_exception_block *new = $<exception_block>3;						new->exc_list = $4;						$$ = new;					}				;proc_exceptions	: proc_exceptions proc_exception						{							$$ = lappend($1, $2);						}				| proc_exception						{							$$ = list_make1($1);						}				;proc_exception	: K_WHEN lno proc_conditions K_THEN proc_sect					{						PLpgSQL_exception *new;						new = palloc0(sizeof(PLpgSQL_exception));						new->lineno     = $2;						new->conditions = $3;						new->action	    = $5;						$$ = new;					}				;proc_conditions	: proc_conditions K_OR opt_lblname						{							PLpgSQL_condition	*old;							for (old = $1; old->next != NULL; old = old->next)								/* skip */ ;							old->next = plpgsql_parse_err_condition($3);							$$ = $1;						}				| opt_lblname						{							$$ = plpgsql_parse_err_condition($1);						}				;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_block_label	:					{						plpgsql_ns_push(NULL);						$$ = NULL;					}				| '<' '<' opt_lblname '>' '>'					{						plpgsql_ns_push($3);						$$ = $3;					}				;/* * need all the options because scanner will have tried to resolve as variable */opt_label	:					{						$$ = NULL;					}				| T_WORD					{						$$ = check_label(yytext);					}				| T_SCALAR					{						$$ = check_label(yytext);					}				| T_RECORD					{						$$ = check_label(yytext);					}				| T_ROW					{						$$ = check_label(yytext);					}				;opt_exitcond	: ';'					{ $$ = NULL; }				| K_WHEN expr_until_semi					{ $$ = $2; }				;opt_lblname		: T_WORD					{						char	*name;						plpgsql_convert_ident(yytext, &name, 1);						$$ = name;					}				;lno				:					{						$$ = plpgsql_error_lineno = plpgsql_scanner_lineno();					}				;%%#define MAX_EXPR_PARAMS  1024/* * determine the expression parameter position to use for a plpgsql datum * * It is important that any given plpgsql datum map to just one parameter. * We used to be sloppy and assign a separate parameter for each occurrence * of a datum reference, but that fails for situations such as "select DATUM * from ... group by DATUM". * * The params[] array must be of size MAX_EXPR_PARAMS. */static intassign_expr_param(int dno, int *params, int *nparams){	int		i;	/* already have an instance of this dno? */	for (i = 0; i < *nparams; i++)	{		if (params[i] == dno)			return i+1;	}	/* check for array overflow */	if (*nparams >= MAX_EXPR_PARAMS)	{		plpgsql_error_lineno = plpgsql_scanner_lineno();		ereport(ERROR,				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),				 errmsg("too many variables specified in SQL statement")));	}	/* add new parameter dno to array */	params[*nparams] = dno;	(*nparams)++;	return *nparams;}PLpgSQL_expr *plpgsql_read_expression(int until, const char *expected){	return read_sql_construct(until, 0, expected, "SELECT ", true, true, NULL);}static PLpgSQL_expr *read_sql_stmt(const char *sqlstart){	return read_sql_construct(';', 0, ";", sqlstart, false, true, NULL);}/* * Read a SQL construct and build a PLpgSQL_expr for it. * * until:		token code for expected terminator * until2:		token code for alternate terminator (pass 0 if none) * expected:	text to use in complaining that terminator was not found * sqlstart:	text to prefix to the accumulated SQL text * isexpression: whether to say we're reading an "expression" or a "statement" * valid_sql:   whether to check the syntax of the expr (prefixed with sqlstart) * endtoken:	if not NULL, ending token is stored at *endtoken *				(this is only interesting if until2 isn't zero) */static PLpgSQL_expr *read_sql_construct(int until,				   int until2,				   const char *expected,				   const char *sqlstart,				   bool isexpression,				   bool valid_sql,				   int *endtoken){	int					tok;	int					lno;	PLpgSQL_dstring		ds;	int					parenlevel = 0;	int					nparams = 0;	int					params[MAX_EXPR_PARAMS];	char				buf[32];	PLpgSQL_expr		*expr;	lno = plpgsql_scanner_lineno();	plpgsql_dstring_init(&ds);	plpgsql_dstring_append(&ds, sqlstart);	for (;;)	{		tok = yylex();		if (tok == until && parenlevel == 0)			break;		if (tok == until2 && parenlevel == 0)			break;		if (tok == '(' || tok == '[')			parenlevel++;		else if (tok == ')' || tok == ']')		{			parenlevel--;			if (parenlevel < 0)				yyerror("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 == ';')		{			if (parenlevel != 0)				yyerror("mismatched parentheses");			plpgsql_error_lineno = lno;			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)));		}		if (plpgsql_SpaceScanned)			plpgsql_dstring_append(&ds, " ");		switch (tok)		{			case T_SCALAR:				snprintf(buf, sizeof(buf), " $%d ",						 assign_expr_param(yylval.scalar->dno,										   params, &nparams));				plpgsql_dstring_append(&ds, buf);				break;			case T_ROW:				snprintf(buf, sizeof(buf), " $%d ",						 assign_expr_param(yylval.row->rowno,										   params, &nparams));				plpgsql_dstring_append(&ds, buf);				break;			case T_RECORD:				snprintf(buf, sizeof(buf), " $%d ",						 assign_expr_param(yylval.rec->recno,										   params, &nparams));				plpgsql_dstring_append(&ds, buf);				break;			default:				plpgsql_dstring_append(&ds, yytext);				break;		}	}	if (endtoken)		*endtoken = tok;	expr = palloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));	expr->dtype			= PLPGSQL_DTYPE_EXPR;	expr->query			= pstrdup(plpgsql_dstring_get(&ds));	expr->plan			= NULL;	expr->nparams		= nparams;	while(nparams-- > 0)		expr->params[nparams] = params[nparams];	plpgsql_dstring_free(&ds);	if (valid_sql)		check_sql_expr(expr->query);	return expr;}static PLpgSQL_type *read_datatype(int tok){	int					lno;	PLpgSQL_dstring		ds;	char			   *type_name;	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)		{			if (parenlevel != 0)				yyerror("mismatched parentheses");			else				yyerror("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 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -