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。
总之,这是个比较琐碎的事情,