Presto - Coordinator 查询流程-2

469 阅读1分钟

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树; image.png

2.2 AstBuilder 转化原始的Tree

将原始由SqlBaseParser.*Context转化成io.trino.sql.tree.*类构成的树;查看AstBuidler的成员变量方法; 经过AstBuidler转化后,Ast的可读性增加,并且也将查询的各部分拆解了出来;(SQL中设置的limit等参数在构建Ast时不会体现在Query中,只会体现在QueryBody)如下截图: image.png 一个完成Query大致结构如下:(":" 号左边是对象属性名,右边是对象类型) image.png