MySQL的多层SP中Cursor的m_max_cursor_index相关BUG分析

源码分析丨MySQL的多层SP中Cursor相关BUG

一、问题发现

在一次开发中在sp中使用多层cursor的时候想知道每层的m_max_cursor_index值分别是多少,以用来做后续开发。于是做了以下的试验,但是发现第一个level=2那层的m_max_cursor_index的值有点问题。

注:本次使用的MySQL数据库版本为最新的debug版本。

SQL语句示例:

greatsql> CREATE TABLE t1 (a INT, b VARCHAR(10));以下注释里面是该层sp_pcontext的参数值。
DELIMITER $$
CREATE PROCEDURE processnames() -- level=0,m_max_cursor_index=1+8+1
BEGINDECLARE nameCursor0 CURSOR FOR SELECT * FROM t1; -- level=1,m_cursor_offset=0,m_max_cursor_index=1+8+1beginDECLARE nameCursor1 CURSOR FOR SELECT * FROM t1; -- level=2,m_cursor_offset=1,m_max_cursor_index=1+8 ☆问题点beginDECLARE nameCursor2 CURSOR FOR SELECT * FROM t1; -- level=3,m_cursor_offset=2,m_max_cursor_index=1DECLARE nameCursor3 CURSOR FOR SELECT * FROM t1; -- level=3,m_cursor_offset=2,m_max_cursor_index=2DECLARE nameCursor4 CURSOR FOR SELECT * FROM t1; -- level=3,m_cursor_offset=2,m_max_cursor_index=3DECLARE nameCursor5 CURSOR FOR SELECT * FROM t1; -- level=3,m_cursor_offset=2,m_max_cursor_index=4end;end;beginDECLARE nameCursor6 CURSOR FOR SELECT * FROM t1; -- level=2,m_cursor_offset=1,m_max_cursor_index=1end;
END $$
DELIMITER ;

首先查看上面的sp的code,可以发现nameCursor6nameCursor1属于同一层,因此他们的offset值一样。

greatsql>  show procedure code processnames;
+-----+---------------------------------------+
| Pos | Instruction                           |
+-----+---------------------------------------+
|   0 | cpush nameCursor0@0: SELECT * FROM t1 |
|   1 | cpush nameCursor1@1: SELECT * FROM t1 |
|   2 | cpush nameCursor2@2: SELECT * FROM t1 |
|   3 | cpush nameCursor3@3: SELECT * FROM t1 |
|   4 | cpush nameCursor4@4: SELECT * FROM t1 |
|   5 | cpush nameCursor5@5: SELECT * FROM t1 |
|   6 | cpop 4                                |
|   7 | cpop 1                                |
|   8 | cpush nameCursor6@1: SELECT * FROM t1 |
|   9 | cpop 1                                |
|  10 | cpop 1                                |
+-----+---------------------------------------+
11 rows in set (6.02 sec)

然后通过debug查看每层sp_pcontext的参数值(相关参数值已经在上面标识出),发现第一个level=2的sp_pcontext的m_max_cursor_index值多了很多,预期值应该是4+1,但是实际是8+1,而上面的层都没错,这说明代码最里面那层m_max_cursor_index赋值错了。

二、问题调查过程

1、发现了问题点就看看代码里面对于每层的m_max_cursor_index是怎么赋值的。

1、初始化sp_pcontext的时候所有的参数都为0
sp_pcontext::sp_pcontext(THD *thd) : m_level(0),m_max_var_index(0),m_max_cursor_index(0)...{init(0, 0, 0, 0);}2、每加一层sp_pcontext,当前的m_cursor_offset=上一层cursor个数
sp_pcontext::sp_pcontext(THD *thd, sp_pcontext *prev,  sp_pcontext::enum_scope scope): m_level(prev->m_level + 1),m_max_var_index(0),m_max_cursor_index(0)... {init(prev->current_cursor_count());}
void sp_pcontext::init(uint cursor_offset) {m_cursor_offset = cursor_offset;}
uint current_cursor_count() const {return m_cursor_offset + static_cast<uint>(m_cursors.size());
}3、退出当前sp_pcontext层,需要把当前的max_cursor_index()信息值赋值给上一层的m_max_cursor_index,即当前的cursor数量累加给上一层
sp_pcontext *sp_pcontext::pop_context() {uint submax = max_cursor_index();if (submax > m_parent->m_max_cursor_index)m_parent->m_max_cursor_index = submax;
}
uint max_cursor_index() const {return m_max_cursor_index + static_cast<uint>(m_cursors.size());}4、每次增加一个cursor,m_max_cursor_index值递增,m_max_cursor_index是计数器。
bool sp_pcontext::add_cursor(LEX_STRING name) {if (m_cursors.size() == m_max_cursor_index) ++m_max_cursor_index;return m_cursors.push_back(name);
}

2、根据第一步的分析,只在最里面那层的m_max_cursor_index累加出来计算错误,看看上面的累加过程,是用max_cursor_index()值来累加的,于是查看max_cursor_index()函数的实现:

uint max_cursor_index() const {return m_max_cursor_index + static_cast<uint>(m_cursors.size());}

这里是把当前层的m_max_cursor_index值加上m_cursors.size(),但是在函数add_cursor里面,m_cursors数组每增加一个cursorm_max_cursor_index都要加1,也就是说在最里面那层sp_pcontext的计算重复了,计算了2遍m_cursors.size(),导致上面的level=2那层的m_max_cursor_index值变成2*4=8了。到这里问题点发现。

三、问题解决方案

通过以上代码解析后,可以考虑只对最里面那层sp_pcontextmax_cursor_index()取值进行修改,最里面那层的sp_pcontext没有m_children,因此可以用这个数组值进行判断。代码作如下修改:

uint max_cursor_index() const {if(m_children.size() == 0) -- 最里面那层sp_pcontext直接返回m_max_cursor_index的值。return m_max_cursor_index; -- 可以改为static_cast<uint>(m_cursors.size()),二者值一样。else -- 上层sp_pcontext返回下层所有sp_pcontext的m_max_cursor_index的值,再加上当前层的m_cursors.size()值。return m_max_cursor_index + static_cast<uint>(m_cursors.size());
}

四、问题总结

在MySQL的sp里面使用cursor的话,因为m_max_cursor_index只用于统计,不用于实际赋值和计算过程,因此不影响使用。但是如果要用这个值用于二次开发,就要注意到这个问题。上面的修改方案只是其中一个解决方案,也可以根据自己的需要去改add_cursor的m_max_cursor_index的赋值过程。

这次发现的问题属于不参与计算的bug,但却影响开源代码的后续开发,在实际开发应用中类似的问题也要注意,一不小心就会踩坑。

Enjoy GreatSQL :)

关于 GreatSQL

GreatSQL是适用于金融级应用的国内自主开源数据库,具备高性能、高可靠、高易用性、高安全等多个核心特性,可以作为MySQL或Percona Server的可选替换,用于线上生产环境,且完全免费并兼容MySQL或Percona Server。

相关链接: GreatSQL社区 Gitee GitHub Bilibili

GreatSQL社区:

image

社区有奖建议反馈: https://greatsql.cn/thread-54-1-1.html

社区博客有奖征稿详情: https://greatsql.cn/thread-100-1-1.html

(对文章有疑问或者有独到见解都可以去社区官网提出或分享哦~)

技术交流群:

微信&QQ群:

QQ群:533341697

微信群:添加GreatSQL社区助手(微信号:wanlidbc )好友,待社区助手拉您进群。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/789062.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot和Vue的房产销售系统的设计与实现

今天要和大家聊的是一款基于SpringBoot和Vue的房产销售系统的设计与实现 &#xff01;&#xff01;&#xff01; 有需要的小伙伴可以通过文章末尾名片咨询我哦&#xff01;&#xff01;&#xff01; &#x1f495;&#x1f495;作者&#xff1a;李同学 &#x1f495;&#x1f…

【Spring实战项目】SpringBoot3整合WebSocket+拦截器实现登录验证!从原理到实战

&#x1f389;&#x1f389;欢迎光临&#xff0c;终于等到你啦&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;持续更新的专栏《Spring 狂野之旅&#xff1a;从入门到入魔》 &a…

MySQL-linux安装-万能RPM法

一、MySQL的Linux版安装 1、 CentOS7下检查MySQL依赖 1. 检查/tmp临时目录权限&#xff08;必不可少&#xff09; 由于mysql安装过程中&#xff0c;会通过mysql用户在/tmp目录下新建tmp_db文件&#xff0c;所以请给/tmp较大的权限。执行 &#xff1a; chmod -R 777 /tmp2. …

Aurora8b10b(2)上板验证

文章目录 前言一、AXI_Stream数据产生模块二、上板效果总结 前言 上一篇内容我们已经详细介绍了基于aurora8b10b IP核的设计&#xff0c;本文将基于此进一步完善并且进行上板验证。 设计思路及代码思路参考FPGA奇哥系列网课 一、AXI_Stream数据产生模块 AXIS协议是非常简单的…

Boost之Log: (3)、简单封装

设计目标: 1、每个Logging source对应一个目录&#xff0c;可以设置日志文件数&#xff0c;日志大小&#xff0c;目录名&#xff0c;文件名等 2、所有logging source日志目录都在一个根目录下。 3、可以动态创建和删除logging source 4、打印出日期时间和日志严重等级 示例代码…

前端试题2#记录

1、介绍以下CSS的盒子模型 盒子模型分为两种&#xff1a; &#xff08;1&#xff09;第一种是W3c标准的盒子模型&#xff08;标准盒模型&#xff09; width和height&#xff1a;内容的宽度、高度&#xff08;不是盒子的宽度、高度&#xff09;。padding&#xff1a;内边距。…

HarmonyOS入门-ArkTS学习(一)

1. 什么是ArkTS语言 学习之前&#xff0c;我们先初步了解下什么是ArkTS 官方指南这样介绍&#xff1a; ArkTS是TS的超集&#xff0c;ArkTS定义了声明式UI描述、自定义组件和动态扩展UI元素的能力&#xff0c;再配合ArkUI开发框架中的系统组件及其相关的事件方法、属性方法等共…

OpenHarmony实战:轻量级系统之子系统移植概述

OpenHarmony系统功能按照“系统 > 子系统 > 部件”逐级展开&#xff0c;支持根据实际需求裁剪某些非必要的部件&#xff0c;本文以部分子系统、部件为例进行介绍。若想使用OpenHarmony系统的能力&#xff0c;需要对相应子系统进行适配。 OpenHarmony芯片适配常见子系统列…

留学生在美国大学利用AI工具到底算不算作弊呢?

自2022年以来&#xff0c;美国大学就开启了一场AI作弊与反作弊大战 战场小至测验&#xff0c;大至申请 这场战争并没有一方胜利&#xff0c;作弊者心思费尽 校方反作弊弄得教授们苦不堪言 那么作为中国留学生该如何避免这场战役呢&#xff1f; 毕竟还是学业要紧呢…… 故事…

让六西格玛培训有效的三个步骤,拿走不谢!

近年来&#xff0c;六西格玛作为一种先进的质量管理方法&#xff0c;被众多企业视为提升产品质量、优化流程、减少浪费的利器。然而&#xff0c;如何使六西格玛培训真正落地生根&#xff0c;发挥出其应有的效果&#xff0c;成为了许多企业关注的焦点。本文&#xff0c;天行健Si…

每日五道java面试题之消息中间件MQ篇(二)

目录&#xff1a; 第一题. RabbitMQ的工作模式第二题. 如何保证RabbitMQ消息的顺序性&#xff1f;第三题. 消息如何分发&#xff1f;第四题. 消息怎么路由&#xff1f;第五题. 如何保证消息不被重复消费&#xff1f;或者说&#xff0c;如何保证消息消费时的幂等性&#xff1f; …

Android adb ime 调试输入法

目录 前言列出所有输入法仅列出输入法 id列出所有输入法的所有信息 启用/禁用 输入法启用输入法禁用输入法 切换输入法还原输入法 前言 安装多个输入法后&#xff0c;可以在设置里进行切换。 既然是开发&#xff0c;能用命令就就命令~ ime 帮助说明&#xff1a; ime <c…

目标检测、识别和语义分割的标注工具安装

计算机视觉 图像分类&#xff08;目标检测&#xff09;&#xff1a;一张图像中是否含某种物体物体定位&#xff08;目标检测与目标识别&#xff09;&#xff1a;确定目标位置和所属类别。语义分割&#xff08;目标分割和目标分类&#xff09;&#xff1a;对图像进行像素级分类…

推荐算法策略需求-rank model优化

1.pred_oobe (base) [rusxx]$ pwd /home/disk2/data/xx/icode/baidu/oxygen/rus-pipeline/pipeline-migrate/UserBaseActiveStatPipeline/his_session (base) [rusxx]$ sh test.sh 2. user_skill_history_dict_expt2包含userid [workxx]$ vim /home/work/xx/du-rus/du_rus_o…

Python 之 Flask 框架学习

毕业那会使用过这个轻量级的框架&#xff0c;最近再来回看一下&#xff0c;依赖相关的就不多说了&#xff0c;直接从例子开始。下面示例中的 html 模板&#xff0c;千万记得要放到 templates 目录下。 快速启动 hello world from flask import Flask, jsonify, url_forapp F…

【edge浏览器无法登录某些网站,以及迅雷插件无法生效的解决办法】

edge浏览器无法登录某些网站&#xff0c;以及迅雷插件无法生效的解决办法 edge浏览器无法登录某些网站&#xff0c;但chrome浏览器可以登录浏览器插件无法使用&#xff0c;比如迅雷如果重装插件重装浏览器重装迅雷后仍然出现问题 edge浏览器无法登录某些网站&#xff0c;但chro…

基于FPGA的SPI_FLASH程序设计

SPI_FLASH简介 spi_flash是一种通用存储器&#xff0c;也称为SPI NOR Flash或SPI Flash。它使用SPI&#xff08;Serial Peripheral Interface&#xff09;接口进行通信&#xff0c;可以通过串行方式读写数据。spi_flash的特点是工作电压低&#xff0c;体积小&#xff0c;读写速…

【单片机家电产品学习记录--红外线】

单片机家电产品学习记录–红外线 红外手势驱动电路&#xff0c;&#xff08;手势控制的LED灯&#xff09; 原理 通过红外线对管&#xff0c;IC搭建的电路&#xff0c;实现灯模式转换。 手势控制灯模式转换&#xff0c;详细说明 转载 1《三色调光LED台灯电路》&#xff0c…

矩阵空间秩1矩阵小世界图

文章目录 1. 矩阵空间2. 微分方程3. 秩为1的矩阵4. 图 1. 矩阵空间 我们以3X3的矩阵空间 M 为例来说明相关情况。目前矩阵空间M中只关心两类计算&#xff0c;矩阵加法和矩阵数乘。 对称矩阵-子空间-有6个3X3的对称矩阵&#xff0c;所以为6维矩阵空间上三角矩阵-子空间-有6个3…

【Turtle】海龟先生

什么是编程 计算机只懂0和1这样的语言&#xff0c;可是我们不懂&#xff0c;当我们希望 计算要能帮我们做事情的时候&#xff0c;该怎么办呢&#xff1f; 我们需要一种更简便的方法告诉计算机要做什么&#xff0c;所以人类发明了编程语言 利用计算机编程语言&#xff0c;我们…