您的位置:首页 > 数据库 > MySQL

MySQL Meta中的length字段 -- (1) 初始值的length计算

2015-09-22 17:50 651 查看
MySQL Meta中的length字段 – (1) 初始值的length计算

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

MySQL Meta中的length字段 – (3) length的推导举例

MySQL Meta中的length字段 – (4) 玩儿MySQL代码

后来的故事 - 想到哪写到哪百孔千疮漏洞百出MySQL MetaData Length实现

后来的故事 - Precision和Length对MySQL执行结果的影响

官方对于length的解释

unsigned int max_length

The maximum length of the result. The default max_length value differs depending on the result type of the function. For string functions, the default is the length of the longest argument. For integer functions, the default is 21 digits. For real functions, the default is 13 plus the number of decimal digits indicated by initid->decimals. (For numeric functions, the length includes any sign or decimal point characters.)

If you want to return a blob value, you can set max_length to 65KB or 16MB. This memory is not allocated, but the value is used to decide which data type to use if there is a need to temporarily store the data.

⬆️来源: http://docs.oracle.com/cd/E17952_01/refman-5.5-en/udf-calling.html

length是什么?

显示一个字段需要的最小字节数。

显示,意味着要转化为字符串;最小,意味着大一点没关系,小了不可以。

length字段的值来源于两方面:

* 初始值

* 推导运算

初始值,也来源于两方面:

* 常量定义

* table column定义

常量定义

见mysql-5.6/sql/sql_yacc.yy,NUM_literal,literal等的定义,如下,Item_int的第三个参数,就是length,可以看到,它的处理方式很直接粗暴,取了literal的length值。

NUM_literal:
NUM
{
int error;
$$= new (YYTHD->mem_root)
Item_int($1,
(longlong) my_strtoll10($1.str, NULL, &error),
$1.length);
if ($$ == NULL)
MYSQL_YYABORT;
}
| LONG_NUM
{
int error;
$$= new (YYTHD->mem_root)
Item_int($1,
(longlong) my_strtoll10($1.str, NULL, &error),
$1.length);
if ($$ == NULL)
MYSQL_YYABORT;
}


mysql> select  -003;
Field   1:  `-003`
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       LONGLONG
Collation:  binary (63)
Length:     4
Max_length: 2
Decimals:   0
Flags:      NOT_NULL BINARY NUM


Table Column定义

代码还是在sql_yacc.cc中

type:
int_type opt_field_length field_options { $$=$1; }
| real_type opt_precision field_options { $$=$1; }
| FLOAT_SYM float_options field_options { $$=MYSQL_TYPE_FLOAT; }
| BIT_SYM
{
Lex->length= (char*) "1";
$$=MYSQL_TYPE_BIT;
}
| BIT_SYM field_length
{
$$=MYSQL_TYPE_BIT;
}
| BOOL_SYM
{
Lex->length= (char*) "1";
$$=MYSQL_TYPE_TINY;
}
| BOOLEAN_SYM
{
Lex->length= (char*) "1";
$$=MYSQL_TYPE_TINY;
}
| char field_length opt_binary
{
$$=MYSQL_TYPE_STRING;
}
| char opt_binary
{
Lex->length= (char*) "1";
$$=MYSQL_TYPE_STRING;
}
| nchar field_length opt_bin_mod
{
$$=MYSQL_TYPE_STRING;
Lex->charset=national_charset_info;
}

field_length:
'(' LONG_NUM ')'      { Lex->length= $2.str; }
| '(' ULONGLONG_NUM ')' { Lex->length= $2.str; }
| '(' DECIMAL_NUM ')'   { Lex->length= $2.str; }
| '(' NUM ')'           { Lex->length= $2.str; };

opt_field_length:
/* empty */  { Lex->length=(char*) 0; /* use default length */ }
| field_length { }
;


全部都是字面长度。对于varchar,也是如此。不过在后面的解析推导过程中,需要注意collation,补乘上collation的最大字节宽度。

Create Table中对应的Column解析代码位于field.cc

/**
Initialize a column definition object. Column definition objects can be used
to construct Field objects.

@param thd                   Session/Thread handle.
@param fld_name              Column name.
@param fld_type              Column type.
@param fld_length            Column length.
@param fld_decimals          Number of digits to the right of the decimal
point (if any.)
@param fld_type_modifier     Additional type information.
@param fld_default_value     Column default expression (if any.)
@param fld_on_update_value   The expression in the ON UPDATE clause.
@param fld_comment           Column comment.
@param fld_change            Column change.
@param fld_interval_list     Interval list (if any.)
@param fld_charset           Column charset.
@param fld_geom_type         Column geometry type (if any.)

@retval
FALSE on success.
@retval
TRUE  on error.
*/

bool Create_field::init(THD *thd, const char *fld_name,
enum_field_types fld_type, const char *fld_length,
const char *fld_decimals, uint fld_type_modifier,
Item *fld_default_value, Item *fld_on_update_value,
LEX_STRING *fld_comment, const char *fld_change,
List<String> *fld_interval_list,
const CHARSET_INFO *fld_charset, uint fld_geom_type)
{

....

if (fld_length != NULL)
{
errno= 0;
length= strtoul(fld_length, NULL, 10);  // SQL中fld_length都是用字符串表示,转成整数
if ((errno != 0) || (length > MAX_FIELD_BLOBLENGTH))
{
my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), fld_name, MAX_FIELD_BLOBLENGTH);
DBUG_RETURN(TRUE);
}

if (length == 0)
fld_length= NULL; /* purecov: inspected */
}

sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1;

switch (fld_type) {
case MYSQL_TYPE_TINY:
if (!fld_length)
length= MAX_TINYINT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;
case MYSQL_TYPE_SHORT:
if (!fld_length)
length= MAX_SMALLINT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;
case MYSQL_TYPE_INT24:
if (!fld_length)
length= MAX_MEDIUMINT_WIDTH+sign_len;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;


SELECT i+j FROM .. 中对应i+j的解析见:sql_yacc.yy

select_item:
remember_name table_wild remember_end
{
THD *thd= YYTHD;

if (add_item_to_list(thd, $2))
MYSQL_YYABORT;
}
| remember_name expr remember_end select_alias
{
THD *thd= YYTHD;
DBUG_ASSERT($1 < $3);

if (add_item_to_list(thd, $2))
MYSQL_YYABORT;
if ($4.str)
{
if (Lex->sql_command == SQLCOM_CREATE_VIEW &&
check_column_name($4.str))
{
my_error(ER_WRONG_COLUMN_NAME, MYF(0), $4.str);
MYSQL_YYABORT;
}
$2->item_name.copy($4.str, $4.length, system_charset_info, false);
}
else if (!$2->item_name.is_set())
{
$2->item_name.copy($1, (uint) ($3 - $1), thd->charset());
}
}
;

/* all possible expressions */
expr:
expr or expr %prec OR_SYM
{
/*
Design notes:
Do not use a manually maintained stack like thd->lex->xxx_list,
but use the internal bison stack ($$, $1 and $3) instead.
Using the bison stack is:
- more robust to changes in the grammar,
- guaranteed to be in sync with the parser state,
- better for performances (no memory allocation).
*/
Item_cond_or *item1;
Item_cond_or *item3;
if (is_cond_or($1))

....

simple_ident:
ident
{
THD *thd= YYTHD;
LEX *lex= thd->lex;
sp_pcontext *pctx = lex->get_sp_current_parsing_ctx();
sp_variable *spv;

if (pctx && (spv= pctx->find_variable($1, false)))
{
Lex_input_stream *lip= &thd->m_parser_state->m_lip;
sp_head *sp= lex->sphead;

DBUG_ASSERT(sp);

/* We're compiling a stored procedure and found a variable */
if (! lex->parsing_options.allows_variable)
{
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
MYSQL_YYABORT;
}

$$=
create_item_for_sp_var(
thd, $1, spv,
sp->m_parser_data.get_current_stmt_start_ptr(),
lip->get_tok_start_prev(),
lip->get_tok_end());

if ($$ == NULL)
MYSQL_YYABORT;

lex->safe_to_cache_query= false;
}
else
{
SELECT_LEX *sel=Select;
if ((sel->parsing_place != IN_HAVING) ||
(sel->get_in_sum_expr() > 0))
{
$$= new (thd->mem_root) Item_field(Lex->current_context(),
NullS, NullS, $1.str);
}
else
{
$$= new (thd->mem_root) Item_ref(Lex->current_context(),
NullS, NullS, $1.str);
}
if ($$ == NULL)
MYSQL_YYABORT;
}
}
| simple_ident_q { $$= $1; }
;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: