欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MySQL的prepare使用及遇到bug解析過程

 更新時間:2022年05月07日 15:36:29   作者:GreatSQL  
在一次開發(fā)中使用 MySQL PREPARE 以后,從 prepare 直接取 name 賦值給 lex->prepared_stmt_name 然后給 EXECUTE 用,發(fā)現有一定概率找不到 prepare stmt 的 name,于是開始動手調查問題發(fā)生的原因,本文給大家分享mysql prepare使用及問題解決,感興趣的朋友一起看看吧

一、問題發(fā)現

在一次開發(fā)中使用 MySQL PREPARE 以后,從 prepare 直接取 name 賦值給 lex->prepared_stmt_name 然后給 EXECUTE 用,發(fā)現有一定概率找不到 prepare stmt 的 name,于是開始動手調查問題發(fā)生的原因。

SQL語句示例:

CREATE TABLE t1 (a INT, b VARCHAR(10));
PREPARE dbms_sql_stmt4 FROM 'INSERT INTO t1 VALUES (1,''11'')';
EXECUTE dbms_sql_stmt4;

報錯:
SQL Error [1243] [HY000]: Unknown prepared statement handler (dbms_sql_stmt4??p??]UU) given to EXECUTE

二、問題調查過程

1、根據報錯信息找到對應源碼,發(fā)現在MySQL_sql_stmt_execute里面有判斷當找不到 stmt name 時候報錯信息。

這里的 name 此時已經是亂碼了。

void MySQL_sql_stmt_execute(THD *thd) {
  LEX *lex = thd->lex;
  const LEX_CSTRING &name = lex->prepared_stmt_name;
  DBUG_TRACE;
  DBUG_PRINT("info", ("EXECUTE: %.*s\n", (int)name.length, name.str));
  Prepared_statement *stmt;
  if (!(stmt = thd->stmt_map.find_by_name(name))) {
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), static_cast<int>(name.length),
             name.str, "EXECUTE");
    return;
  }

2、這個 lex->prepared_stmt_name 是從 prepare name 中賦值的,于是調查 prepare 這個 name 設置的函數。

bool Prepared_statement::set_name(const LEX_CSTRING &name_arg) {
  m_name.length = name_arg.length;
  m_name.str = static_cast<char *>(
      memdup_root(m_arena.mem_root, name_arg.str, name_arg.length));
  return m_name.str == nullptr;
}

gdb 跟蹤代碼:

Thread 46 "MySQLd" hit Breakpoint 1, Prepared_statement::set_name (this=0x7fff2cbf3250, name_arg=...)
    at /home/wuyy/greatdb/gitmerge/percona-server/sql/sql_prepare.cc:2447
2447	bool Prepared_statement::set_name(const LEX_CSTRING &name_arg) {
(gdb) n
2448	  m_name.length = name_arg.length;
(gdb) 
2450	      memdup_root(m_arena.mem_root, name_arg.str, name_arg.length));
(gdb) 
2449	  m_name.str = static_cast<char *>(
(gdb) 
2451	  return m_name.str == nullptr;
(gdb) p m_name
$9 = {
  str = 0x7fff2cd09a68 "dbms_sql_stmt4", '\217' <repeats 98 times>, "FLOAT",
  length = 14
# 可以看到 m_name 后面出現了亂碼,說明 m_nam e最后不是 \0 結束,而是別的字符。

3、接著到 execute 的函數看一下這個 name 值,發(fā)現確實后面跟的不是 \0 結束符,而是變?yōu)閬y碼。于是這里當然會報錯找不到該 stmt name 了。

Thread 46 "MySQLd" hit Breakpoint 2, MySQL_sql_stmt_execute (thd=0x7fff2c002688)
    at /home/wuyy/greatdb/gitmerge/percona-server/sql/sql_prepare.cc:1944
1944	void MySQL_sql_stmt_execute(THD *thd) {
(gdb) n
1945	  LEX *lex = thd->lex;
(gdb) 
1946	  const LEX_CSTRING &name = lex->prepared_stmt_name;
(gdb) 
1947	  DBUG_TRACE;
(gdb) p name
$10 = (const LEX_CSTRING &) @0x7fff2cd501e0: {
  str = 0x7fff2cd09a68 "dbms_sql_stmt4\217\217p\271\221]UU",
  length = 22
}
(gdb) n
1948	  DBUG_PRINT("info", ("EXECUTE: %.*s\n", (int)name.length, name.str));
(gdb) 
1951	  if (!(stmt = thd->stmt_map.find_by_name(name))) {
(gdb) 
1953	             name.str, "EXECUTE");
(gdb) 
1952	    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), static_cast<int>(name.length),
(gdb) 
1954	    return;
# 結果報錯了。

三、問題解決方案

通過以上 gdb 跟蹤過程我們可以發(fā)現 prepare 存 name 的時候存放方式有問題導致 name 最后沒有結束符,于是回頭看一下set_name 的代碼,于是發(fā)現以下代碼問題:

bool Prepared_statement::set_name(const LEX_CSTRING &name_arg) {
  m_name.length = name_arg.length;
  m_name.str = static_cast<char *>(
      memdup_root(m_arena.mem_root, name_arg.str, name_arg.length));←這里問題
  return m_name.str == nullptr;
}
# 箭頭處發(fā)現存 name 時候申請的內存長度為 name_arg.length,沒有把最后的 \0 一起存放進去,導致最后少了結束符,這就有概率導致查找 name 出錯。

于是把 name_arg.length 改為 name_arg.length+1,重新編譯代碼問題解決。

四、問題總結

c++ 中字符串的使用一定要注意最后的結束符\0,如果因為少分配了一個長度導致結束符沒有存進去,最后存放的字符串就會產生問題。

到此這篇關于MySQL的prepare使用及遇到bug解析過程的文章就介紹到這了,更多相關mysql prepare使用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 深入解析MySQL的窗口函數

    深入解析MySQL的窗口函數

    這篇文章主要介紹了深入解析MySQL的窗口函數,窗口可以理解為記錄集合,窗口函數就是在滿足某種條件的記錄集合上執(zhí)行的特殊函數,即:應用在窗口內的函數,需要的朋友可以參考下
    2023-07-07
  • CentOS 安裝redis和MySQL

    CentOS 安裝redis和MySQL

    這篇文章主要介紹了CentOS 安裝redis和MySQL的相關資料,需要的朋友可以參考下
    2019-08-08
  • MySQL數據庫開啟、關閉、查看函數功能的方法

    MySQL數據庫開啟、關閉、查看函數功能的方法

    這篇文章主要介紹了MySQL數據庫開啟、關閉、查看函數功能的方法,本文為解決一個錯誤總結而來,錯誤信息本文一同給出,需要的朋友可以參考下
    2014-10-10
  • MySQL結合使用數據庫分析工具SchemaSpy的方法

    MySQL結合使用數據庫分析工具SchemaSpy的方法

    這篇文章主要介紹了MySQL結合使用數據庫分析工具SchemaSpy的方法,需要的朋友可以參考下
    2015-06-06
  • MYSQL存儲過程 注釋詳解

    MYSQL存儲過程 注釋詳解

    這篇文章主要介紹MYSQL存儲的過程,本文圍繞MYSQL存儲詳細展開文章內容,并附上詳細代碼解析,需要的下伙伴可以參考一下,希望對你有所幫助
    2021-10-10
  • SQL中distinct 和 row_number() over() 的區(qū)別及用法

    SQL中distinct 和 row_number() over() 的區(qū)別及用法

    這篇文章主要介紹了SQL中distinct 和 row_number() over() 的區(qū)別及用法的相關資料,需要的朋友可以參考下
    2017-03-03
  • 實例驗證MySQL|update字段為相同的值是否會記錄binlog

    實例驗證MySQL|update字段為相同的值是否會記錄binlog

    這篇文章主要介紹了實例驗證MySQL|update字段為相同的值是否會記錄binlog,幫助大家更好的理解和學習MySQL數據庫,感興趣的朋友可以了解下
    2020-10-10
  • MySql安裝及登錄詳解

    MySql安裝及登錄詳解

    這篇文章主要介紹了MySql安裝及登錄詳解,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-03-03
  • MySQL同步數據Replication的實現步驟

    MySQL同步數據Replication的實現步驟

    本文主要介紹了MySQL同步數據Replication的實現步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03
  • MySQL InnoDB 事務鎖源碼分析

    MySQL InnoDB 事務鎖源碼分析

    InnoDB 事務鎖,事務鎖實現起來的代碼卻是又臭又硬的好大一坨,各種細節(jié),今天小編在這里整理一個源碼閱讀筆記,把那一坨加鎖相關的代碼提煉出來,感興趣的小伙伴別忘記收藏奧
    2021-09-09

最新評論