SQL 语句经过词法分析解析后,会转化成 Token 序列作为语法分析器的输入,语法分析器加载所有的语法规则,根据内部定义的解析策略对 Token 序列进行解析,对于 SQL 查询语句,常见的语法错误:
下面是 SqlBase.g4 文件中关于 SQL 查询语法规则定义的部分片段:
# 匹配 SQL 查询片段
querySpecification
: SELECT setQuantifier? selectItem (',' selectItem)* # 带分隔符的序列模式
(FROM relation (',' relation)*)? # 嵌套模式
(WHERE where=booleanExpression)?
(GROUP BY groupBy)?
(HAVING having=booleanExpression)?
;
# 选择模式:从 DISTINCT 和 ALL 选择 1 个
setQuantifier
: DISTINCT
| ALL
;
selectItem
: expression (AS? identifier)? # 别名
| qualifiedName '.' ASTERISK # 某个表的所有列
| ASTERISK # 所有列
;
expression
: booleanExpression
;
# 带分隔符的序列模式
qualifiedName
: identifier ('.' identifier)*
;
# 选择模式
identifier
: IDENTIFIER
| QUOTED_IDENTIFIER
| nonReserved
| BACKQUOTED_IDENTIFIER
| DIGIT_IDENTIFIER
;
IDENTIFIER
: (LETTER | '_') (LETTER | DIGIT | '_' | '@' | ':')*
;
fragment DIGIT
: [0-9]
;
fragment LETTER
: [A-Z]
;
relation
: left=relation
( CROSS JOIN right=sampledRelation
| joinType JOIN rightRelation=relation joinCriteria
| NATURAL joinType JOIN right=sampledRelation
)
| sampledRelation
;
sampledRelation
: aliasedRelation (
TABLESAMPLE sampleType '(' percentage=expression ')'
)?
;
aliasedRelation
: relationPrimary (AS? identifier columnAliases?)?
;
# 选择模式
relationPrimary
: qualifiedName
| '(' query ')'
| UNNEST '(' expression (',' expression)* ')' (WITH ORDINALITY)?
| LATERAL '(' query ')'
| '(' relation ')'
;
复制代码
将上面的语法规则转为思维导图,可以直观的查看语法规则的详细分支:
上篇文章解析的 Token 序列,结合这个思维导图,下面是语法分析器使用 LL 最左推导由上到下的解析过程:
语法分析器首先会加载所有已定义的语法规则;
对 Token 序列进行遍历解析;
语法分析器按照默认的语法规则向下进行匹配;
首个 Token 匹配到 SELECT 非保留字,接着会对 id,name,address,age 7 个 Token 进行校验:匹配到路径 selectItem (',' selectItem)* -> selectItem -> booleanExpression -> valueExpression -> primaryExpression -> identifier -> IDENTIFIER -> LETTER,校验通过;
匹配到 FROM 非保留字,接着会对 mysql.ice.user
进行校验: 匹配到路径 sampledRelation -> aliasedRelation -> relationPrimary -> qualifiedName -> identifier ('.' identifier)*,校验通过;
匹配到 WEREH 非保留字,接着会匹配后面的表达式;
遍历到末尾,解析工作结束。
本系列文章:
Presto 设计与实现(一):开篇
Presto 设计与实现(二):一切从 0 开始?
Presto 设计与实现(三):依赖注入框架 Guice
Presto 设计与实现(四):动态代码生成 ByteBuddy
Presto 设计与实现(五):自动配置
Presto 设计与实现(六):JMX
Presto 设计与实现(七):Event
Presto 设计与实现(八):Presto JDBC
Presto 设计与实现(九):SQL 词法分析
Presto 设计与实现(十):SQL 语法分析
Presto 设计与实现(十一):抽象语法树 AST
Presto 设计与实现(十二):SQL 逻辑计划
评论