技术分享 | 浅谈mysql语法解析调试方法
欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答
本文向您介绍一种利用mysql解析器和bison的调试选项进行sql语法解析跟踪的方法。
数据库开发过程中我们常会遇到修改sql语法的需求。我们知道,mysql的sql解析器是基于yacc文法,采用EBNF格式进行规则描述(sql/sql_yacc.yy),并借助bison工具生成(sql_yacc.h, sql_yacc.cc), 所以修改sql语法,不可避免地要和这些yacc文法打交道,对sql_yacc.yy进行改造升级。
yacc文法是对语法解析的高度概括,它为我们修改解析器提供了一种优雅的方式,但与此同时当我们遇到语句解析问题,通常比较难直接从抽象的语法规则中找到原因。幸运的是,结合mysql和bison提供的调试工具,我们有机会将整个语法解析的过程形象化,通过解析日志,yacc规则和自动状态机的对应,能够比较快地完成问题的定位。
mysql解析器调试开关
sql/sql_yacc.yy文件下,可以看到如下一段代码:
#ifndef NDEBUG
void turn_parser_debug_on()
{
/*
MYSQLdebug is in sql/sql_yacc.cc, in bison generated code.
Turning this option on is **VERY** verbose, and should be
used when investigating a syntax error problem only.
The syntax to run with bison traces is as follows :
- Starting a server manually :
mysqld --debug="d,parser_debug" ...
- Running a test :
mysql-test-run.pl --mysqld="--debug=d,parser_debug" ...
The result will be in the process stderr (var/log/master.err)
*/
extern int yydebug;
yydebug= 1;
}
#endif
它告诉我们,debug版本下,在mysqld启动时添加 -debug="d, parser_debug选项,数据库服务器会为我们输出sql解析的具体信息(bison traces)。
这里我们使用一条简单的sql语句SELECT 1+2*3 FROM DUAL 作为例子,看它的日志输出信息(注:’#‘号后为后添加的说明,非原始信息),开头部分如下:
#注:SQL语句会首先被词法解析器(LEXER)处理,输出'SELECT_SYM NUM + NUM * NUM FROM DUAL_SYM'这样的序列,作为语法解析器的输出
Starting parse #语句解析开始
Entering state 0
Reading a token: Next token is token SELECT_SYM (: ) # 读入SELECT
Shifting token SELECT_SYM (: ) # 移进SELECT
Entering state 42 # 栈用于记录当前推导情况
Reading a token: Next token is token NUM (: ) # 读入NUM(第一个数字'1'的词法解析标记)
Reducing stack by rule 1377 (line 10001): # 在读入之前,做一次栈规约(使用的规则在sql_yacc.yy的10001行)
-> $$ = nterm select_options (: )
Stack now 0 42
Entering state 1013 # 栈规约后,进入新的状态
...
输出信息里state 42, 1013等信息,yacc语法自动状态机里的状态编号,为了查看它,我们需要使用到bison工具手动生成自动状态机文件。
- 自动状态机文件
使用bison的 -v 选项,得到语法的自动状态机文件,生成方式示例如下:
cd ${SOURCE_DIR}/sql #SOURCE_DIR 为mysql源码目录位置
/usr/bin/bison --name-prefix=MYSQL --yacc --warnings=all,no-yacc,no-empty-rule,no-precedence,no-deprecated --defines=${BUILD_DIR}/sql/sql_yacc.h -v sql_yacc.yy #BUILD_DIR为用户自定的编译目录位置
执行成功后,将在${SOURCE_DIR}/sql下生成一个名为y.output的文件,该文件描述了bison根据语法规则计算得出的状态机描述文件,在文件里我们会看到:
1.带编号的语法规则描述。如前文提及的rule 1377,在文件中的内容为:
1377 select_options: %empty
它表示可以将一个空的产生式规约为select_option
2.所有自动机状态。前文提及的state 42,在文件中显示为:
State 42
1366 query_specification: SELECT_SYM . select_options select_item_list into_clause opt_from_clause opt_where_clause opt_group_clause opt_having_clause opt_window_clause
...
ALL shift, and go to state 1004
...
select_options go to state 1013
select_option_list go to state 1014
select_option go to state 1015
query_spec_option go to state 1016
3.带shift/reduce,reduce/reduce冲突的状态统计:
State 27 conflicts: 2 shift/reduce
State 42 conflicts: 2 shift/reduce
State 220 conflicts: 2 shift/reduce
本文测试使用的是mysql-8.0.25, 它现存的shift/reduce冲突总共为66个,mysql不鼓励因为语法修改而使状态机产生任何新的冲突,因此在开发过程中需要多加注意:
/*
1. We do not accept any reduce/reduce conflicts
2. We should not introduce new shift/reduce conflicts any more.
%expect 66
*/
有了mysql提供的栈信息,结合bison -v 生成的状态机文件,我们就可以将语法解析过程中的某个具体节点的推导路径给打印出来,如我们可以将解析器在处理完SELECT_SYM NUM +后,准备读入NUM前的推导过程(栈状态为:0 42 1013)整理如下(注:"." 位置左边,可以看做当前状态已经移进或者规约的内容):

这样,我们就能够比较清晰的知道,在sql解析的每个阶段,解析器的具体状态,因此当出现语法修改错误时,就能够很容易地定位到自己规则哪一部分出现异常,进而更快速地解决问题。
Enjoy GreatSQL
本文由博客一文多发平台 OpenWrite 发布!
技术分享 | 浅谈mysql语法解析调试方法的更多相关文章
- 技术分享 | 浅谈MySQL闪回的实现
欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 1.闪回实现原理 2.binlog文件格式初探 3.闪回实现过程 1.闪回实现原 ...
- 浅谈mysql主从复制的高可用解决方案
1.熟悉几个组件(部分摘自网络)1.1.drbd —— DRBD(Distributed Replicated Block Device),DRBD号称是 "网络 RAID" ...
- 浅谈mysql innodb缓存策略
浅谈mysql innodb缓存策略: The InnoDB Buffer Pool Innodb 持有一个存储区域叫做buffer pool是为了在内存中缓存数据和索引,知道innodb buffe ...
- 浅谈mysql配置优化和sql语句优化【转】
做优化,我在这里引用淘宝系统分析师蒋江伟的一句话:只有勇于承担,才能让人有勇气,有承担自己的错误的勇气.有承担错误的勇气,就有去做事得勇气.无论做什么事,只要是对的,就要去做,勇敢去做.出了错误,承担 ...
- 浅谈MySQL中优化sql语句查询常用的30种方法 - 转载
浅谈MySQL中优化sql语句查询常用的30种方法 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使 ...
- 浅谈Mysql共享锁、排他锁、悲观锁、乐观锁及其使用场景
浅谈Mysql共享锁.排他锁.悲观锁.乐观锁及其使用场景 Mysql共享锁.排他锁.悲观锁.乐观锁及其使用场景 一.相关名词 |--表级锁(锁定整个表) |--页级锁(锁定一页) |--行级锁(锁 ...
- 浅谈 js 正则之 test 方法
原文:浅谈 js 正则之 test 方法 其实我很少用这个,所以之前一直没注意这个问题,自从落叶那厮写了个变态的测试我才去看了下这东西.先来看个东西吧. var re = /\d/; console. ...
- [原创]浅谈H5页面性能优化方法
[原创]浅谈H5页面性能优化方法 前阶段公司H5页面性能测试,其中测试时也发现了一些性能瓶颈问题,接下来我们在来谈谈H5页面性能优化,仅仅是一些常用H5页面性能优化措施,其实和Web页面性能优化思路大 ...
- 【转】浅谈Java中的hashcode方法(这个demo可以多看看)
浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native i ...
随机推荐
- 832. Flipping an Image - LeetCode
Question 832. Flipping an Image Solution 题目大意:将1列与最后n列对换,2列与n-1列对换-然后再将每个元素取反 思路:遍历二维数组的左半边,对每个元素先做对 ...
- 个人冲刺(四)——体温上报app(二阶段)
冲刺任务:完成用户注册功能和数据库类 RegisterActivity.java package com.example.helloworld; import android.content.Inte ...
- 解决 AMD 笔记本不插电源时屏幕偏暗的问题
办法:关掉显卡设置里的 Vari-Bright 选项 最近换了锐龙版的笔记本,用着还不错,就是不插电源时看屏幕亮度不太适应,整体偏暗,有点费眼,差点就觉得 AMD 不 Yes 了.然后网上一顿找,发现 ...
- DirectX11 With Windows SDK--40 抗锯齿:FXAA
前言 在默认的情况下渲染,会看到物体的边缘会有强烈的锯齿感,究其原因在于采样不足.但是,尝试提升采样的SSAA会增大渲染的负担:而硬件MSAA与延迟渲染又不能协同工作.为此我们可以考虑使用后处理的方式 ...
- CSS中html的标签元素分类
在CSS中,html中的标签元素大体被分为三种不同的类型: 块状元素.内联元素(又叫行内元素)和内联块状元素. 常用的块状元素有: <div>.<p>.<h1&g ...
- Makefile基础语法
Makefile的作用 如果没有Makefile,每次修改源代码后,如果要重新编译代码,都要输入编译命令,当源代码很多时,效率很底下. 基本格式 target: componsnts TAB rule ...
- 1. Docker的中央仓库安装设置及镜像的操作
具体也可参考:https://developer.aliyun.com/mirror/docker-ce?spm=a2c6h.13651102.0.0.3e221b11G7cfhr https://d ...
- ExtJS 布局-Accordion布局(Accordion layout)
更新记录: 2022年6月2日 开始. 2022年6月3日 发布. 1.说明 accordion(手风琴)布局一次仅显示一个子组件,内置支持 折叠 和 展开.当需要堆叠多个子组件,并每次只显示一次时, ...
- Django从数据库导model迁移乱码
python manage.py inspectdb > [your app name]\models.py 执行后 model.py乱码,将models.py以 UTF-16LE打开.
- 关于使用koa 跨域问题你可能会遇到
var cors = require('koa2-cors');// 跨域const allowOrigins = ["http://localhost:8080" // 需要跨域 ...