前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Postgresql源码(50)语法解析时关键字判定原理(函数名不能使用的关键字为例)

Postgresql源码(50)语法解析时关键字判定原理(函数名不能使用的关键字为例)

作者头像
mingjie
发布2022-05-26 07:57:33
7730
发布2022-05-26 07:57:33
举报
文章被收录于专栏:Postgresql源码分析

相关: 《Postgresql源码(44)server端语法解析流程分析》 《Postgresql源码(50)语法解析时关键字判定原理(函数名不能使用的关键字为例)》

关键字报错场景

关键字不出现,或出现在函数内部:创建成功

代码语言:javascript
复制
CREATE OR REPLACE FUNCTION fn1(x int) RETURNS int AS $$
BEGIN
    RETURN x;
END;
$$ LANGUAGE plpgsql;
postgres=# CREATE FUNCTION

CREATE OR REPLACE FUNCTION fn2(x int) RETURNS int AS $$
DECLARE
    normalize int;
BEGIN
    RETURN x;
END;
$$ LANGUAGE plpgsql;
postgres=# CREATE FUNCTION

关键字出现在函数名、函数参数中:创建失败

代码语言:javascript
复制
CREATE OR REPLACE FUNCTION fn2(normalize int) RETURNS int AS $$
BEGIN
    RETURN normalize;
END;
$$ LANGUAGE plpgsql;
postgres=# ERROR:  syntax error at or near "normalize"
postgres=# LINE 1: CREATE OR REPLACE FUNCTION fn2(normalize int) RETURNS int AS...


CREATE OR REPLACE FUNCTION normalize(x int) RETURNS int AS $$
BEGIN
    RETURN x;
END;
$$ LANGUAGE plpgsql;
postgres=# ERROR:  syntax error at or near "normalize"
postgres=# LINE 1: CREATE OR REPLACE FUNCTION fn2(normalize int) RETURNS int AS...

解析过程分析

已创建失败的函数normalize为例,分析语法解析过程

CREATE OR REPLACE FUNCTION normalize(x int) RETURNS int AS $$

调试方法参考:《Postgresql源码(44)server端语法解析流程分析》

解析过程总结:

代码语言:javascript
复制
[lex]
CREATE = 352
OR = 544
REPLACE = 595
FUNCTION = 429
==========================================
[yacc]
opt_or_replace:
    OR REPLACE                { $$ = true; }
    | /*EMPTY*/               { $$ = false; }
		;
==========================================
[lex]
IDENT = 258
(
==========================================
[yacc]
type_function_name:	IDENT             { $$ = $1; }      <--------- 走这里
      | unreserved_keyword            { $$ = pstrdup($1); }
      | type_func_name_keyword        { $$ = pstrdup($1); }
      ;

func_name:	type_function_name
          { $$ = list_make1(makeString($1)); }         <--------- 走这里
      ...
		;

从下面这里开始有问题了,函数名normalize被解析成关键字了,base_yylex返回的是NORMALIZE,如果是普通函数名应该返回IDENT。

lex返回522后,yacc语法树没有匹配项了,返回错误。

代码语言:javascript
复制
[lex]
NORMALIZE = 522
[yacc]
if (!yyerrstatus)
{
  ++yynerrs;
  yyerror (&yylloc, yyscanner, YY_("syntax error"));
  ...
}

判定原理

base_yylex调用core_yylex解析时,如果匹配到关键字,就会返回gram.c中enum yytokentype的关键字。

core_yylex需要返回它遇到的标识符类型并将其值存储在yylval中,这些标识符在gram.y中定义:

代码语言:javascript
复制
gram.y

%token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
	AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
	ASENSITIVE ASSERTION ASSIGNMENT ASYMMETRIC ATOMIC AT ATTACH ATTRIBUTE AUTHORIZATION
  ...

这些标识符主要是给lex使用的,在lex匹配到正则规则时,返回其中一个token。

所有的关键字都在gram.y文件中使用%token表示了,这些关键字应该都不能用于 表名、列名等对象名等,可能会造成shift/reduce冲突。但其实很多也不会触发冲突,为了使用这些关键字,在gram.y文件后面专门定义了几组语法规则:

  • unreserved_keyword:可以用于任意命名场景,如果新增的关键字不会引发shift/reduce冲突,可以放在这个列表中。
  • col_name_keyword:可用于列名、表名,但不能用于函数名。
  • type_func_name_keyword:可用于函数名、类型名。
  • reserved_keyword:只能用于列别名(例如:select name as all from tbl;)
  • bare_label_keyword:只能用于列名,但可以省略as(例如:select name all from tbl;)
代码语言:javascript
复制
unreserved_keyword:
			  ABORT_P
			| ABSOLUTE_P
			| ACCESS
			| ACTION
			| ADD_P
			...

col_name_keyword:
			  BETWEEN
			| BIGINT
			| BIT
			| BOOLEAN_P
			| CHAR_P
			| CHARACTER
      ...

type_func_name_keyword:
			  AUTHORIZATION
			| BINARY
			| COLLATION
			| CONCURRENTLY
			| CROSS
			...

reserved_keyword:
			  ALL
			| ANALYSE
			| ANALYZE
			| AND
			| ANY
			| ARRAY
		  ...

bare_label_keyword:
			  ABORT_P
			| ABSOLUTE_P
			| ACCESS
			| ACTION
			| ADD_P
			| ADMIN
			| AFTER
			...

kwlist.h 的增加方法

创建新关键字时需要在kwlist.h中增加PG_KEYWORD。

增加方法:先确定新增关键字会不会造成语法冲突歧义等,加到上面5个list中,然后根据能否用于表名、列名、as等场景,在kwlist中增加即可。

代码语言:javascript
复制
/* name, value, category, is-bare-label */
PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, BARE_LABEL)
PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, BARE_LABEL)
...
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关键字报错场景
  • 解析过程分析
  • 判定原理
  • kwlist.h 的增加方法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档