一、問題描述
root@mysqldb 22:12: [xucl]> show create table t1/G*************************** 1. row *************************** Table: t1Create Table: CREATE TABLE `t1` ( `id` varchar(255) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf81 row in set (0.00 sec) root@mysqldb 22:19: [xucl]> select * from t1;+--------------------+| id |+--------------------+| 204027026112927605 || 204027026112927603 || 2040270261129276 || 2040270261129275 || 100 || 101 |+--------------------+6 rows in set (0.00 sec)
奇怪的現象:
root@mysqldb 22:19: [xucl]> select * from t1 where id=204027026112927603;+--------------------+| id |+--------------------+| 204027026112927605 || 204027026112927603 |+--------------------+2 rows in set (0.00 sec)640?wx_fmt=jpeg

什么鬼,明明查的是204027026112927603,為什么204027026112927605也出來了
二、源碼解釋
堆棧調用關系如下所示:

其中JOIN::exec()是執行的入口,Arg_comparator::compare_real()是進行等值判斷的函數,其定義如下
int Arg_comparator::compare_real(){ /* Fix yet another manifestation of Bug#2338. 'Volatile' will instruct gcc to flush double values out of 80-bit Intel FPU registers before performing the comparison. */ volatile double val1, val2; val1= (*a)->val_real(); if (!(*a)->null_value) { val2= (*b)->val_real(); if (!(*b)->null_value) { if (set_null) owner->null_value= 0; if (val1 < val2) return -1; if (val1 == val2) return 0; return 1; } } if (set_null) owner->null_value= 1; return -1;}比較步驟如下圖所示,逐行讀取t1表的id列放入val1,而常量204027026112927603存在于cache中,類型為double類型(2.0402702611292762E+17),所以到這里傳值給val2后val2=2.0402702611292762E+17。

當掃描到第一行時,204027026112927605轉成doule的值為2.0402702611292762e17,等式成立,判定為符合條件的行,繼續往下掃描,同理204027026112927603也同樣符合

如何檢測string類型的數字轉成doule類型是否溢出呢?這里經過測試,當數字超過16位以后,轉成double類型就已經不準確了,例如20402702611292711會表示成20402702611292712(如圖中val1)


MySQL string轉成double的定義函數如下:
{ char buf[DTOA_BUFF_SIZE]; double res; DBUG_ASSERT(end != NULL && ((str != NULL && *end != NULL) || (str == NULL && *end == NULL)) && error != NULL); res= my_strtod_int(str, end, error, buf, sizeof(buf)); return (*error == 0) ? res : (res < 0 ? -DBL_MAX : DBL_MAX);}真正轉換函數my_strtod_int位置在dtoa.c(太復雜了,簡單貼個注釋吧)
新聞熱點
疑難解答