
openGauss内核分析(三):SQL解析
在传统数据库中SQL引擎一般指对用户输入的SQL语句进行解析、优化的软件模块。
SQL的解析过程主要分为:
- 词法分析Lexical Analysis:将用户输入的SQL语句拆解成单词(Token)序列,并识别出关键字、标识、常量等。
- 语法分析Syntax Analysis:分析器对词法分析器解析出来的单词(Token)序列在语法上是否满足SQL语法规则。
- 语义分析Semantic Analysis:语义分析是SQL解析过程的一个逻辑阶段,主要任务是在语法正确的基础上进行上下文有关性质的审查,在SQL解析过程中该阶段完成表名、操作符、类型等元素的合法性判断,同时检测语义上的二义性。
openGauss在pg_parse_query中调用raw_parser函数对用户输入的SQL命令进行词法分析和语法分析,生成语法树添加到链表parsetree_list中。完成语法分析后,对于parsetree_list中的每一颗语法树parsetree,会调用parse_analyze函数进行语义分析,根据SQL命令的不同,执行对应的入口函数,最终生成查询树。
词法分析Lexical Analysis
openGauss使用flex工具进行词法分析。flex工具通过对已经定义好的词法文件进行编译,生成词法分析的代码。词法文件是scan.l,它根据SQL语言标准对SQL语言中的关键字、标识符、操作符、常量、终结符进行了定义和识别。在kwlist.h中定义了大量的关键字,按照字母的顺序排列,方便在查找关键字时通过二分法进行查找。在scan.l中处理“标识符”时,会到关键字列表中进行匹配,如果一个标识符匹配到关键字,则认为是关键字,否则才是标识符,即关键字优先. 以“select a, b from item”为例说明词法分析结果。
名称 | 词性 | 内容 | 说明 |
关键字 | keyword | SELECT,FROM | 如SELECT/FROM/WHERE等,对大小写不敏感 |
标识符 | IDENT | a,b,item | 用户自己定义的名字、常量名、变量名和过程名,若无括号修饰则对大小写不敏感 |
语法分析Syntax Analysis
openGauss中定义了bison工具能够识别的语法文件gram.y,根据SQL语言的不同定义了一系列表达Statement的结构体(这些结构体通常以Stmt作为命名后缀),用来保存语法分析结果。以SELECT查询为例,它对应的Statement结构体如下。
这个结构体可以看作一个多叉树,每个叶子节点都表达了SELECT查询语句中的一个语法结构,对应到gram.y中,它会有一个SelectStmt。代码如下:
从simple_select语法分析结构可以看出,一条简单的查询语句由以下子句组成:去除行重复的distinctClause、目标属性targetList、SELECT INTO子句intoClause、FROM子句fromClause、WHERE子句whereClause、GROUP BY子句groupClause、HAVING子句havingClause、窗口子句windowClause和plan_hint子句。在成功匹配simple_select语法结构后,将会创建一个Statement结构体,将各个子句进行相应的赋值。对simple_select而言,目标属性、FROM子句、WHERE子句是最重要的组成部分。SelectStmt与其他结构体的关系如下:
下面以“select a, b from item”为例说明简单select语句的解析过程,函数exec_simple_query调用pg_parse_query执行解析,解析树中只有一个元素。
List中的节点类型为T_SelectStmt
查看SelectStmt结构体,targetList 和fromClause非空
查看SelectStmt的targetlist,有两个ResTarget
查看SelectStmt的fromClause,有一个RangeVar
综合以上分析可以得到语法树结构
语义分析Semantic Analysis
在完成词法分析和语法分析后,parse_analyze函数会根据语法树的类型,调用transformSelectStmt将parseTree改写为查询树。
得到的查询树结构如下:
完成词法、语法和语义分析后,SQL解析过程完成,SQL引擎开始执行查询优化。
文章转载自公众号: openGauss
