首页 > 数据库 > MySQL > 正文

解析MySQL隐式转换问题

2024-07-24 12:41:40
字体:
来源:转载
供稿:网友

一、问题描述

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(太复杂了,简单贴个注释吧)

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表