一、问题引入
二、代码跟踪
三、总结
一、问题引入
今天遇到一个很奇怪的问题,在MySQL客户端输入,用不同科学计数法表示的数值,展示效果却截然不同:
代码语言:javascript复制mysql> select 1e 14,1e 15;
----------------- -------
| 1e 14 | 1e 15 |
----------------- -------
| 100000000000000 | 1e15 |
----------------- -------
为什么都是用科学计数法,一个是用完全展开的形式表示,另外一个却变成用科学计数法来表示?
二、代码跟踪
我们知道,在MySQL中解析这类科学计数法的标识token,是通过BISON来进行词法和语法解析的,并最终转成Item类型,Item构造初始化的堆栈如下所示:
代码语言:javascript复制#0 Item_float::init (this=0x7fffe844e8c0, str_arg=0xe7f312c00e0f8 <error: Cannot access memory at address 0xe7f312c00e0f8>, length=21845) at /home/greatdb/sql/item.cc:7216
#1 0x0000555559260095 in Item_float::Item_float (this=0x7fff2c00dad8, pos=..., str_arg=0x7fff2c00dac8 "1.234e-14", length=9) at /home/greatdb/sql/item.h:5237
#2 0x00005555592503af in MYSQLparse (YYTHD=0x7fff2c001040, parse_tree=0x7fffe84506b0) at /home/greatdb/sql/sql_yacc.yy:16616
#3 0x0000555558ea2410 in THD::sql_parser (this=0x7fff2c001040) at /home/greatdb/sql/sql_class.cc:3149
#4 0x0000555558fe8126 in parse_sql (thd=0x7fff2c001040, parser_state=0x7fffe8450990, creation_ctx=0x0) at /home/greatdb/sql/sql_parse.cc:7391
#5 0x0000555558fe1f16 in dispatch_sql_command (thd=0x7fff2c001040, parser_state=0x7fffe8450990, update_userstat=false) at /home/greatdb/sql/sql_parse.cc:5293
#6 0x0000555558fd7969 in dispatch_command (thd=0x7fff2c001040, com_data=0x7fffe8451b70, command=COM_QUERY) at /home/greatdb/sql/sql_parse.cc:1994
#7 0x0000555558fd5cd9 in do_command (thd=0x7fff2c001040) at /home/greatdb/sql/sql_parse.cc:1442
#8 0x00005555591fffc6 in handle_connection (arg=0x555560992ff0) at /home/greatdb/sql/conn_handler/connection_handler_per_thread.cc:307
#9 0x000055555ae2314b in pfs_spawn_thread (arg=0x5555608507a0) at /home/greatdb/storage/perfschema/pfs.cc:2899
#10 0x00007ffff77c3609 in start_thread (arg=<optimized out>) at pthread_create.c:477
#11 0x00007ffff76e8133 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
我们仔细看下面这个函数的实现:
代码语言:javascript复制void Item_float::init(const char *str_arg, uint length) {
int error;
const char *end_not_used;
//经过观察,我们发现:不管是1e 14还是1e 15,这里把字符串转成浮点数,都是完全展开形式。
//即1e 14展开为100000000000000
//1e 15展开为1000000000000000
//说明至少到目前为止,没有触发展示差异的原因。
value = my_strntod(&my_charset_bin, str_arg, length, &end_not_used, &error);
if (error) {
char tmp[NAME_LEN 1];
snprintf(tmp, sizeof(tmp), "%.*s", length, str_arg);
my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "double", tmp);
}
presentation.copy(str_arg, length);
item_name.copy(str_arg, length);
set_data_type(MYSQL_TYPE_DOUBLE);
decimals = (uint8)nr_of_decimals(str_arg, str_arg length);
max_length = length;
fixed = true;
}
接着我们继续查看Item处理结果的堆栈信息:
代码语言:javascript复制#0 my_gcvt (x=100000000000000, type=MY_GCVT_ARG_DOUBLE, width=342, to=0x7fffe844ec60 "