MySQL8语法硬编码高性能解析器

本文介绍了手写的MySQL8解析器的实现,包括词法分析、语法分析和抽象语法树(AST)的构建。解析器参考了Cobar的解析器并采用byte流解析,支持DML、DDL语法。通过深度优先遍历AST,使用Visitor模式处理SQL语义。文章还讨论了Lexer的功能设计和状态机工作原理,并提及SQL优化的可能性,如拦截‘永真’表达式。
摘要由CSDN通过智能技术生成

解析器

代码地址 👉 GitHub地址:DagonParser

即Parser,和计算机科学中的编译原理这门课关联比较多。

网上常见的解析器有Cobar的解析器、Druid的解析器、还有一些选择采用一些工具生成的解析器,比如说 ANTLR,只需要描述好语法规则,这个工具就能生成对应的编译器。

下面介绍的解析器是手撸的,目前也实现了DML、DDL语法(持续更新中),语法参考MySQL8.0官方文档上的语法,项目组成部分参考Cobar的解析器,但是转为byte流来解析。

解析器的三个重要组成部分,它们分别是:

  • Parser
  • Lexer(词法分析)
  • Syntax(语法分析)
  • AST(Abstract Syntax Tree)抽象语法树
  • Visitor
    关系图

词法分析:

举例说明,SQL语句:select id from merchant

拿到这条SQL语句后,需要解析出每个独立的单词,select、id、from、merchant。Keywords就是以上在SQL中具有重要意义的单词,某些关键字,如SELECT, DELETE或 BIGINT,被保留,需要用作标识符,例如表和列名特殊待遇。这里将需要保留的keywords统一称为token、不需要保留的称为keywords。解析独立单词的过程,就称为词法分析。

语法分析:

对于解析器来说呢,它不仅需要知道每个单词,而且要知道这些单词组合在一起后,表达了什么含义。语法分析的职责就是明确一个语句的语义,表达的是什意思。

自然语言和形式语言的一个重要区别是,自然语言的一个语句,可能有多重含义,而形式语言的一个语句,只能有一个语义;形式语言的语法是人为规定的,有了一定的语法规则,语法解析器就能根据语法规则,解析出一个语句的一个唯一含义。

AST:

AST (抽象语法树)是 Parser 的产物,语句经过词法分析,语法分析后,它的结构需要以一种计算机能读懂的方式表达出来,最常用的就是抽象语法树。

一个语句,它由哪些部分组成?其中一个组成部分又有哪些部分组成?

例如一条 select 语句,它由 select 列表、where 子句、order by排序字段、group by分组字段等组成,而 select 列表则由一个或多个 select 项组成,where 子句又由一个或者多个 where条件组成。
这种组成结构就是一个总分的逻辑结构,用树来表达,最合适不过。对于计算机来说,处理树也是最方便的。

AST 仅仅是语义的表示,但如何对这个语义进行表达,便需要去访问这棵 AST,看它到底表达什么含义。

通常遍历语法树,使用 Visitor 模式去遍历,从根节点开始遍历,一直到最后一个叶子节点,在遍历的过程中,便不断地收集信息到一个上下文中,整个遍历过程完成后,对这棵树所表达的语法含义,已经被保存到上下文了。我这边解析器的遍历方式主要为深度优先遍历,进行byte流的拼接。

快速入门

MySQL8.0官方文档的SELECT语法
在这里插入图片描述

demo test

public class MySQLDemoParserTest extends AbstractSyntaxTest {
   

    public void test() throws Exception {
   
        //byte流
        byte[] sql = "select id from merchant".getBytes();
        //语法解析(包含词法解析)
        Tuple2<List<SQLStatement>, Exception> tuple = Parser.parse(sql, MySqlCharset.UTF8_FOR_JAVA);
        assertNotNull(tuple);
        assertNotNull(tuple._1());
        assertNull(tuple._2());
        assertEquals(tuple._1().size(), 1);
        //获取AST树
        DMLSelectStatement select = (DMLSelectStatement)tuple._1().get(0);
        //遍历输出AST树
        String output = outputMySQL(select, sql);
        assertEquals("SELECT id FROM merchant", output);
    }

}


public class AbstractSyntaxTest extends TestCase {
   

    private static final boolean debug =
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值