欢迎来到 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. 好客租房57-props深入(4props的默认值)

    1给props设置默认值 //导入react     import React from 'react'     import ReactDOM from 'react-dom'     import ...

  2. MASA Auth - 权限设计

    权限术语 Subject:用户,用户组 Action:对Object的操作,如增删改查等 Object:权限作用的对象,也可以理解为资源 Effect:规则的作用,如允许,拒绝 Condition:生 ...

  3. Python数据分析--Numpy常用函数介绍(4)--Numpy中的线性关系和数据修剪压缩

    摘要:总结股票均线计算原理--线性关系,也是以后大数据处理的基础之一,NumPy的 linalg 包是专门用于线性代数计算的.作一个假设,就是一个价格可以根据N个之前的价格利用线性模型计算得出. 前一 ...

  4. Java基础(1)——ThreadLocal

    1. Java基础(1)--ThreadLocal 1.1. ThreadLocal ThreadLocal是一个泛型类,当我们在一个类中声明一个字段:private ThreadLocal<F ...

  5. 关于spring整合mybatis

    第一步导入依赖 <dependencies> <dependency> <groupId>org.mybatis</groupId> <artif ...

  6. JAVA - 请说明”static”关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法?

    请说明"static"关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法? "static"关键字表明一个成 ...

  7. 剖析虚幻渲染体系(15)- XR专题

    目录 15.1 本篇概述 15.1.1 本篇内容 15.1.2 XR概念 15.1.2.1 VR 15.1.2.2 AR 15.1.2.3 MR 15.1.2.4 XR 15.1.3 XR综述 15. ...

  8. 集成学习——Adaboost(手推公式)

  9. SpringBoot 整合文件上传 elment Ui 上传组件

    SpringBoot 整合文件上传 elment Ui 上传组件 本文章记录 自己学习使用 侵权必删! 前端代码 博主最近在学 elment Ui 所以 前端使用 elmentUi 的 upload ...

  10. flex大法:一网打尽所有常见布局

    flex全称Flexible Box模型,顾名思义就是灵活的盒子,不过一般都叫弹性盒子,所有PC端及手机端现代浏览器都支持,所以不用担心它的兼容性,有了这玩意,妈妈再也不用担心我们的布局. 先简单介绍 ...