MySQL Meta中的length字段 -- (2) length的推导

MySQL Meta中的length字段 – (1) 初始值的length计算
MySQL Meta中的length字段 – (2) length的推导
MySQL Meta中的length字段 – (3) length的推导举例
MySQL Meta中的length字段 – (4) 玩儿MySQL代码


上一篇讲了初始值的length计算,有了初始值的length后,就有条件对更复杂表达式的length进行推导了。

主要有这么不同的几类运算:

  • 算术运算,如加减乘除
  • 逻辑运算,如and、is
  • 比较运算,如大于、between
  • 字符串运算,如concat、substr
  • 多值选择运算,如coalesce、case when

这些运算位于如下几个文件里

  • mysql-5.6/sql/item_func.cc
  • mysql-5.6/sql/item_cmpfunc.cc
  • mysql-5.6/sql/item_strfunc.cc

例如,对于乘法:

void Item_func_mul::result_precision()
{
  /* Integer operations keep unsigned_flag if one of arguments is unsigned */
  if (result_type() == INT_RESULT)
    unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag;
  else
    unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag;
  decimals= min(args[0]->decimals + args[1]->decimals, DECIMAL_MAX_SCALE);
  uint est_prec = args[0]->decimal_precision() + args[1]->decimal_precision();
  uint precision= min<uint>(est_prec, DECIMAL_MAX_PRECISION);
  max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
                                                           unsigned_flag);
}

inline uint32 my_decimal_precision_to_length_no_truncation(uint precision,
                                                           uint8 scale,
                                                           bool unsigned_flag)
{
  /*
    When precision is 0 it means that original length was also 0. Thus
    unsigned_flag is ignored in this case.
  */
  DBUG_ASSERT(precision || !scale);
  return (uint32)(precision + (scale > 0 ? 1 : 0) +
                  (unsigned_flag || !precision ? 0 : 1));
}
// 上面这段逻辑为什么这样写?
// 下文末尾有详细解说:
// http://blog.csdn.net/maray/article/details/49179821


uint Item::decimal_precision() const
{
  Item_result restype= result_type();

  if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT))
  {
    uint prec=
      my_decimal_length_to_precision(max_char_length(), decimals,
                                     unsigned_flag);
    return min<uint>(prec, DECIMAL_MAX_PRECISION);
  }
  switch (field_type())
  {
    case MYSQL_TYPE_TIME:
      return decimals + TIME_INT_DIGITS;
    case MYSQL_TYPE_DATETIME:
    case MYSQL_TYPE_TIMESTAMP:
      return decimals + DATETIME_INT_DIGITS;
    case MYSQL_TYPE_DATE:
      return decimals + DATE_INT_DIGITS;
    default:
      break;
  }
  return min<uint>(max_char_length(), DECIMAL_MAX_PRECISION);
}

class Item_int :public Item_num
{
public:
  longlong value;
  Item_int(const Name_string &name_arg, longlong i, uint length) :value(i)
  {
    max_length= length;
    item_name= name_arg;
    fixed= 1;
  }
  uint decimal_precision() const
  { return (uint)(max_length - MY_TEST(value < 0)); }
  bool eq(const Item *, bool binary_cmp) const;
  bool check_partition_func_processor(uchar *bool_arg) { return FALSE;}
};

class Item_uint :public Item_int
{
public:
  Item_uint(const Name_string &name_arg, longlong i, uint length)
    :Item_int(name_arg, i, length) { unsigned_flag= 1; }
  uint decimal_precision() const { return max_length; }
};


uint32 max_char_length() const
{ return max_length / collation.collation->mbmaxlen; }

inline uint my_decimal_length_to_precision(uint length, uint scale,
                                           bool unsigned_flag)
{
  /* Precision can't be negative thus ignore unsigned_flag when length is 0. */
  DBUG_ASSERT(length || !scale);
  return (uint) (length - (scale>0 ? 1:0) -
                 (unsigned_flag || !length ? 0:1));
}

上面几个辅助函数在计算length的时候很常见,需要非常熟悉其行为。

对于比较类、大部分逻辑运算,length都是固定值1。

总之,这是个比较琐碎的事情,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值