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 逻辑计划
评论