MySQL 源码|32 - 探索过程记录(词法解析阶段)

探索 1|Query_blockQuery_expression

Step 1|查阅资料: MySQL源码解析之执行计划 - GreatSQL - 博客园,了解到 bool JOIN::optimize() 是优化器的入口函数,阅读其中逻辑,推测 Query_expression 可能是存储 SQL 语句的对象。考虑优先了解 Query_expression 的逻辑。

Step 2|阅读 Query_block 的源码,发现其为 Query_block 相互大量引用,而 Query_block 又是 Query_term 的子类且与 Query_term 相互大量引用。因此,先了解 Query_blockQuery_expressionQuery_term 共同构成的查询树结构。

探索 2|LEX 结构体

Step 1|因为 Query_block 是存储单个 SQL 语句的对象,那么构造该对象的位置应该就是 SQL 语句解析的部分。Query_block 构造方法的两次调用都发生在 LEX 的成员函数 new_empty_query_blockcreate_query_expr_and_block 中。

Step 2|在 LEX 结构体的注释中,介绍了 LEX 对象的声明周期,所以按生命周期梳理各个元素的顺序。

Step 3|在 LEX 结构体中,有成员 m_tok_start 被注释为 “Starting position of the last token parsed”,说明这个成员被用于解析,搜索这个成员的使用位置,发现在 LEX::start_token()LEX::restart_token()LEX::get_tok_start()LEX::yyLength() 方法中被使用,然后发现这 4 个函数主要在 lex_one_token() 函数或该函数调用的其他方法中被调用,但是在 sql/sql_lex.ccrouter/src/routing/src/sql_lexer.cc 中有两套 lex_one_token() 解析函数。从引用关系来看,sql_lexer.cc 中的 lex_one_token() 应该是主要解析逻辑。

探索 3|词法解析

Step 1|阅读 lex_one_token() 函数,可以看到 Lex_input_stream 类型指针 lip 存储了解析过程的状态,并在函数中大量使用。

Step 2|在 lex_one_token() 中大量使用了文本扫描器(Lex_input_stream)和 CHARSET_INFO

Step 3lex_one_token() 函数的核心就是词法解析的自动机。

Step 4lex_one_token() 函数的调用位置

探索 4|寻找语法解析

Step 1|根据词法解析器,可知句法解析器一定要依托 SqlLexer::iterator 迭代器,全局搜索引入 SqlLexer::iterator,除了 sql_lexer.cc 外,有如下位置使用:

  • \router\src\routing\src\classic_query_forwarder.cc:除 DEBUG_DUMP_TOKEN 外,仅在 contains_multiple_statements 函数中使用
  • \router\src\routing\src\classic_query_sender.cc:逻辑均在 DEBUG_DUMP_TOKEN
  • \router\src\routing\src\sql_parser.h:使用于 SqlParser 类的成员中

其中,直观推断 SQLParser 类更接近语法解析的概率更高。

Step 2SQLParser 的 4 个子类中应该包含解析逻辑,但是看起来都不是词法解析的主逻辑位置,而应该是 4 个工具类,具体地:

Step 3|继续分析这 4 个子类的调用位置,发现都集中到了 classic_query_forwarder.ccQueryForwarder::command() 中。查看 QueryForwarder 类,发现其中有一个名为 Stage 的枚举类,推断是 SQL 命令的执行过程,因此推断 QueryForarder 类是 MySQL 的执行过程。QueryForarderForwardingProcessor 的子类,ForwardingProcessorProcessor 的子类,ProcessorBasicProcessor 的子类。我们从已经了解的 4 个解析器向调用位置逐步了解逻辑。

Step 4QueryForarder::command() 函数在 QueryForwarder::process() 函数中被调用,而 QueryForwarder::process() 函数没有被直接调用,且 QueryForwarder 类在 classic_query_forward.ccclassic_query_forward.h 文件外,仅在 CommandProcessor::command() 函数中被调用。下面我们了解 Processor 类的一些基础信息。

Step 5|在 QueryForarder::command() 函数中没有语法解析逻辑。至此,我们已经尝试了如下 3 个方向:

  • 通过追溯调用词法解析逻辑的位置,寻找词法解析的逻辑,但是只找到了权限判断、判断是否开启事务、判断是否隐式提交、判断是否发出警告信息的解析器,而没有主要的解析器逻辑
  • 通过追溯调用 Query_blockQuery_expression 的逻辑,但是我们也没有在相关位置找到语法解析逻辑
  • 通过反查 SELECT_SYMUNIQUE_SYM 的全局使用位置,但是也不再有其他包含的位置了

但是,SELECT_SYMUNIQUE_SYMsql_yacc.yy 中还有使用,搜索后发现如下文章 MySQL 源码解读之-语法解析(二),确定 sql_yacc.yy 是 bison 规则文件,正是语法解析逻辑的位置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值