欢迎来到 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语法解析调试方法的更多相关文章

  1. 技术分享 | 浅谈MySQL闪回的实现

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 1.闪回实现原理 2.binlog文件格式初探 3.闪回实现过程 1.闪回实现原 ...

  2. 浅谈mysql主从复制的高可用解决方案

    1.熟悉几个组件(部分摘自网络)1.1.drbd     —— DRBD(Distributed Replicated Block Device),DRBD号称是 "网络 RAID" ...

  3. 浅谈mysql innodb缓存策略

    浅谈mysql innodb缓存策略: The InnoDB Buffer Pool Innodb 持有一个存储区域叫做buffer pool是为了在内存中缓存数据和索引,知道innodb buffe ...

  4. 浅谈mysql配置优化和sql语句优化【转】

    做优化,我在这里引用淘宝系统分析师蒋江伟的一句话:只有勇于承担,才能让人有勇气,有承担自己的错误的勇气.有承担错误的勇气,就有去做事得勇气.无论做什么事,只要是对的,就要去做,勇敢去做.出了错误,承担 ...

  5. 浅谈MySQL中优化sql语句查询常用的30种方法 - 转载

    浅谈MySQL中优化sql语句查询常用的30种方法 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使 ...

  6. 浅谈Mysql共享锁、排他锁、悲观锁、乐观锁及其使用场景

    浅谈Mysql共享锁.排他锁.悲观锁.乐观锁及其使用场景   Mysql共享锁.排他锁.悲观锁.乐观锁及其使用场景 一.相关名词 |--表级锁(锁定整个表) |--页级锁(锁定一页) |--行级锁(锁 ...

  7. 浅谈 js 正则之 test 方法

    原文:浅谈 js 正则之 test 方法 其实我很少用这个,所以之前一直没注意这个问题,自从落叶那厮写了个变态的测试我才去看了下这东西.先来看个东西吧. var re = /\d/; console. ...

  8. [原创]浅谈H5页面性能优化方法

    [原创]浅谈H5页面性能优化方法 前阶段公司H5页面性能测试,其中测试时也发现了一些性能瓶颈问题,接下来我们在来谈谈H5页面性能优化,仅仅是一些常用H5页面性能优化措施,其实和Web页面性能优化思路大 ...

  9. 【转】浅谈Java中的hashcode方法(这个demo可以多看看)

    浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native i ...

随机推荐

  1. 基于 BaGet 搭建 Nuget 服务器

    1 前言 1.1 BaGet 介绍 BaGet 是一个轻量级的,开源的,跨平台的 Nuget 和 symbol 服务器. 1.2 环境介绍 操作系统:CentOS 7 使用 Docker 安装 2 安 ...

  2. Grafana+Prometheus 搭建 JuiceFS 可视化监控系统

    作为承载海量数据存储的分布式文件系统,用户通常需要直观地了解整个系统的容量.文件数量.CPU 负载.磁盘 IO.缓存等指标的变化. JuiceFS 没有重复造轮子,而是通过 Prometheus 兼容 ...

  3. 配置中心Nacos(服务发现)

    服务演变之路 单体应用架构 在刚开始的时候,企业的用户量.数据量规模都⽐较⼩,项⽬所有的功能模块都放在⼀个⼯程中编码.编译.打包并且部署在⼀个Tomcat容器中的架构模式就是单体应用架构,这样的架构既 ...

  4. MyCat应用实战

    下载Mycat https://github.com/MyCATApache/Mycat-Server/releases Mycat基础分库 基础配置 修改server.xml <user na ...

  5. Mac 睡眠唤醒 不睡眠 问题

    问题 之前一直有夜晚睡觉前电脑关机的习惯,主要是想着电脑也跟人一样️要休息.然后最近想着自己 Mac 干脆每天睡眠算了,省得每天开关机麻烦,所以就最近这段时间每次夜晚睡觉前主动去点了电脑的 「Slee ...

  6. 解决Mysql搭建成功后执行sql语句报错以及区分大小写问题

    刚搭建完mysql 8.0以后会: 一.表区分大小写, 二.执行正确的sql语句成功且会报:[Err] 1055 - Expression #1 of ORDER BY clause is not i ...

  7. STM32内存知识

    在了解STM32内存之前需要了解 MCU 的型号和MDK 中的.map 文件,很多刚学习 stm32 时都不会过多的去了解 MCU 的选型,是在太枯燥了.这里在从新了解一下,久了就熟悉了. 一.STM ...

  8. 合宙AIR105(二): 时钟设置和延迟函数

    目录 合宙AIR105(一): Keil MDK开发环境, DAP-Link 烧录和调试 合宙AIR105(二): 时钟设置和延迟函数 Air105 的时钟 高频振荡源 芯片支持使用内部振荡源, 或使 ...

  9. Android multiple back stacks导航的几种实现

    Android multiple back stacks导航 谈谈android中多栈导航的几种实现. 什么是multiple stacks 当用户在app里切换页面时, 会需要向后回退到上一个页面, ...

  10. ASP.NET MVC之model传值view

    控制器中,我们有时会在知道用户名的情况下,再获取相关数据 例如: public ActionResult Index()        {            UserInfo Entity_Tem ...