成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

MySQL的多層SP中Cursor的m_max_cursor_index相關BUG分析

數據庫 MySQL
在MySQL的sp里面使用cursor的話,因為m_max_cursor_index?只用于統計,不用于實際賦值和計算過程,因此不影響使用。但是如果要用這個值用于二次開發,就要注意到這個問題。

一、問題發現

在一次開發中在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
BEGIN
    DECLARE nameCursor0 CURSOR FOR SELECT * FROM t1; -- level=1,m_cursor_offset=0,m_max_cursor_index=1+8+1
    begin
    DECLARE nameCursor1 CURSOR FOR SELECT * FROM t1; -- level=2,m_cursor_offset=1,m_max_cursor_index=1+8 ☆問題點
       begin
   DECLARE nameCursor2 CURSOR FOR SELECT * FROM t1; -- level=3,m_cursor_offset=2,m_max_cursor_index=1
            DECLARE nameCursor3 CURSOR FOR SELECT * FROM t1; -- level=3,m_cursor_offset=2,m_max_cursor_index=2
            DECLARE nameCursor4 CURSOR FOR SELECT * FROM t1; -- level=3,m_cursor_offset=2,m_max_cursor_index=3
            DECLARE nameCursor5 CURSOR FOR SELECT * FROM t1; -- level=3,m_cursor_offset=2,m_max_cursor_index=4
        end;
    end;
    begin
  DECLARE nameCursor6 CURSOR FOR SELECT * FROM t1; -- level=2,m_cursor_offset=1,m_max_cursor_index=1
    end;
END $$
DELIMITER ;

首先查看上面的sp的code,可以發現nameCursor6和nameCursor1屬于同一層,因此他們的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數組每增加一個cursor,m_max_cursor_index都要加1,也就是說在最里面那層sp_pcontext的計算重復了,計算了2遍m_cursors.size(),導致上面的level=2那層的m_max_cursor_index值變成2*4=8了。到這里問題點發現。

三、問題解決方案

通過以上代碼解析后,可以考慮只對最里面那層sp_pcontext的max_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,但卻影響開源代碼的后續開發,在實際開發應用中類似的問題也要注意,一不小心就會踩坑。

責任編輯:武曉燕 來源: GreatSQL社區
相關推薦

2025-03-17 10:01:07

2024-05-08 08:56:09

GreatSQL內存宏定義

2025-01-03 08:50:23

2025-05-14 16:39:21

2023-07-05 08:21:24

MySQL函數sp

2025-06-06 08:13:47

2025-04-07 02:30:00

Cursor前端

2025-05-09 08:21:29

2023-11-15 17:23:30

測試軟件開發

2025-03-19 09:14:15

CursorTun模式LLM

2011-04-19 15:38:16

MongodbCursor

2024-12-23 08:01:27

2025-05-23 09:32:44

2025-04-29 08:11:15

2022-11-14 14:36:59

數據集Python自相關

2025-01-02 14:10:41

2022-08-18 20:21:33

MySQLpreparebug

2024-10-08 08:35:00

模型訓練

2025-06-13 08:44:37

2023-12-04 08:11:16

Oracle數據庫
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲视频欧美视频 | 免费在线观看一区二区 | 羞羞视频网站免费观看 | 韩国欧洲一级毛片 | 久久久精品一区二区三区 | 人妖一区 | 国产欧美日韩一区二区三区在线观看 | 久久久久久久电影 | 黄色毛片免费看 | a国产一区二区免费入口 | 麻豆久久久9性大片 | 午夜精品一区二区三区在线视频 | 国产三级 | 国产成人一区二区三区 | www中文字幕 | 欧美日韩久久 | 欧美激情亚洲天堂 | 日韩在线一区二区三区 | 毛片一区二区 | 亚洲成年影院 | 国产精品视频在 | 成人免费网站www网站高清 | 国产精品久久久久久 | 日韩一区二区三区视频 | 国产精品爱久久久久久久 | 亚洲午夜精品一区二区三区他趣 | 欧美精品中文字幕久久二区 | 在线观看免费国产 | 亚洲欧美一区二区三区视频 | 国产乱码精品一区二区三区五月婷 | caoporn国产精品免费公开 | 久久国产激情视频 | 免费黄色a视频 | 国产精品99久久久久久久vr | 国产精品永久久久久 | 99久久精品国产一区二区三区 | 欧美午夜精品久久久久久浪潮 | 91精品麻豆日日躁夜夜躁 | 国产精品99久久久久久人 | 精品久久国产 | 精品视频一区二区三区在线观看 |