想到哪写到哪百孔千疮漏洞百出MySQL MetaData Length实现

这是一篇吐槽贴
吐槽的对象是MySQL
吐槽的点是它计算length的算法
结论是:这代码写得,真是想到哪写到哪,千疮百孔,漏洞百出。

以substr为例:

mysql> select substr('1234', 4, 9);
Field   1:  `substr('1234', 4, 9)`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       VAR_STRING
Collation:  utf8_general_ci (33)
Length:     27
Max_length: 1
Decimals:   31
Flags:


+----------------------+
| substr('1234', 4, 9) |
+----------------------+
| 4                    |
+----------------------+
1 row in set (0.00 sec)

可以看到,substr的length输出为27。可是,就算把1234全部输出出来,也不可能为27呀!那么,27是怎么来的呢? 看代码吧。代码我加了一些注释,可以看到它是如何计算length的。


void Item_func_substr::fix_length_and_dec()
{
  // 例子:select substr('1234', 4, 9);
  // note:max_length对应的就是上面meta data中的length。
  max_length=args[0]->max_length;  //  max_length = 12 = 4 * 3 = 4 * mbmaxlen

  agg_arg_charsets_for_string_result(collation, args, 1);
  DBUG_ASSERT(collation.collation != NULL);
  if (args[1]->const_item())
  {
    int32 start= (int32) args[1]->val_int();
    if (args[1]->null_value)
      goto end;
    if (start < 0)
      max_length= ((uint)(-start) > max_length) ? 0 : (uint)(-start);
    else
      max_length-= min((uint)(start - 1), max_length); // max_length = 12 - 3 = 9
  }
  if (arg_count == 3 && args[2]->const_item())
  {
    int32 length= (int32) args[2]->val_int();
    if (args[2]->null_value)
      goto end;
    if (length <= 0)
      max_length=0;
    else
      set_if_smaller(max_length,(uint) length);  // max_length = min(9, 9) = 9, 
      // 这里啰嗦一句,当第三个参数大于9的时候,max_length总是保持在27这个值上,就是这一句min作祟。
  }

end:
  max_length*= collation.collation->mbmaxlen; // max_length = 9 * 3 = 27
}

看完上面的分析,就知道27是怎么算出来的了:collation->mbmaxlen会被乘多次。满满的一碗bug,来,干了!

MySQL开发者为什么写出这样的代码来呢?其实它在某种情况下计算结果是正确的,例如:select substr(1234, 4, 9); 详见本文评论。

这并不是个案,MySQL中计算length很随意,几乎就是实现定义的。那么问题来了,我要兼容这种length bug算法吗?如果不兼容,那么我们是否应该有一套规范?如果兼容,你来写。


附,额外思考题:

如果不是用常量,而是用变量来代入第二个第三个参数呢?例如:

substr('1234', col\_start, col\_length);

从代码上看,输出length应该是12,因为col_start和col_length在fix_length_and_dec()阶段都无法确定具体值,所以只能使用最保守的长度了。

这种做法,价值何在?


补记:http://blog.csdn.net/maray/article/details/49891793 本文弄明白了价值何在。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值