1.总体介绍
上接:Presto - Coordinator 查询流程-1,上章节总体介绍了Coordinator中查询流程的大致步骤,同时分析了查询入口部分代码,接下来进入查询的语法分析部分;本章重点介绍Presto使用Antrl4将SQL语句转化成原生AST,然后使用AstBuidler将Antlr原生的表达式树转化成Presto自定义Ast; 了解Antlr4查看从一个小例子理解Antlr4
2.语法分析
2.1 使用Antlr4解析SQL语句
SqlParser#createStatement是语法分析的入口; 如下代码所示,首先使用SQL初始化Parser,然后使用SLL Mode 如果异常再使用 LL Mode 解析Ast树;
public Statement createStatement(String sql, ParsingOptions parsingOptions)
{
return (Statement) invokeParser("statement", sql, SqlBaseParser::singleStatement, parsingOptions);
}
private Node invokeParser(String name, String sql, Function<SqlBaseParser, ParserRuleContext> parseFunction, ParsingOptions parsingOptions)
{
// 生成SQL对应的parser
SqlBaseLexer lexer = new SqlBaseLexer(new CaseInsensitiveStream(CharStreams.fromString(sql)));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
SqlBaseParser parser = new SqlBaseParser(tokenStream);
initializer.accept(lexer, parser);
...
// 首先使用 SLL Mode对 parser进行解析,语法树;若是报错,使用LL Mode解析语法树
ParserRuleContext tree;
try {
// first, try parsing with potentially faster SLL mode
parser.getInterpreter().setPredictionMode(PredictionMode.SLL);
tree = parseFunction.apply(parser);
}
catch (ParseCancellationException ex) {
// if we fail, parse with LL mode
tokenStream.seek(0); // rewind input stream
parser.reset();
parser.getInterpreter().setPredictionMode(PredictionMode.LL);
tree = parseFunction.apply(parser); // Tree的结构如下图所示
}
// 使用AstBuidler 遍历树
return new AstBuilder(parsingOptions).visit(tree);
}
举个例子,假设SQLSELECT * FROM STUDENT WHERE SEX='男' LIMIT 2,在解析是对应的Ast树;
2.2 AstBuilder 转化原始的Tree
将原始由SqlBaseParser.*Context转化成io.trino.sql.tree.*类构成的树;查看AstBuidler的成员变量方法; 经过AstBuidler转化后,Ast的可读性增加,并且也将查询的各部分拆解了出来;(SQL中设置的limit等参数在构建Ast时不会体现在Query中,只会体现在QueryBody)如下截图:
一个完成Query大致结构如下:(":" 号左边是对象属性名,右边是对象类型)