sql请求发送到server端,需要经过解析器生成内部的数据结构对象,以方便进行优化和生成执行计划。解析器主要做了两件事情,词法分析和语法分析。
词法和语法分析:mysql使用lex词法分析器,yacc语法分析器进行分析,最后保存到lex对象结构中。
例如: select id, name from xpchild where
id=1
1.
在mysql_parse函数中使用lex_start初始化thd->lex对象,然后调用yacc中的MYSQLparse函数进行词法和语法分析。
sql_yacc.cc是yacc在编译后生成出来的源文件,而在sql_yacc.yy文件中定义了大量的语法规则。下面找到select的语法定义。
2. 语法解析部分:
根据词法分析器的分析后的结果,应用下面的语法规则
%token SELECT_SYMselect:
select_init
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
};select_item_list:
select_item_list ‘,‘ select_item
| select_item
| ‘*‘
{
THD *thd= YYTHD;
Item *item= new (thd->mem_root) Item_field(&thd->lex->current_select->context,NULL, NULL, "*");
if (item == NULL)
MYSQL_YYABORT;
if (add_item_to_list(thd, item))
MYSQL_YYABORT;
(thd->lex->current_select->with_wild)++;
};where_clause:
/* empty */ { Select->where= 0; }
| WHERE
{
Select->parsing_place= IN_WHERE;
}
expr
{
SELECT_LEX *select= Select;
select->where= $3;
select->parsing_place= NO_MATTER;
if ($3)
$3->top_level_item();
};
可以看到,上面的sql语句被解析出来的几个部分:(保存在lex结构中)
1. sql_command=SQLCOM_SELECT;
2. where子句:select_lex->where
3. table列表:select_lex->table_list
4. 字段列表:select_lex->item_list
具体内容:
1. table_list
(gdb) print select_lex->table_list
$33 = {
<Sql_alloc> = {<No data fields>},
members of SQL_I_List<TABLE_LIST>:
elements = 1,
first = 0x8ca04818,
next = 0x8ca04818
只有一个table, db = 0x8ca04bc8 "test", table_name =
0x8ca047f0 "xpchild"
2. where
(gdb) print select_lex->where->type()
$32 = Item::FUNC_ITEM
(gdb) p select_lex->where)->args))->type()
$30 = Item::FIELD_ITEM
(gdb) p select_lex->where)->args++))->type()
$29 = Item::INT_ITEM
结构如下:
where
|-->FUNC_ITEM
|-->FIELD_ITEM("id")
|-->INT_ITEM(1)
3. item_list
(gdb) print *(Item_field*)(select_lex->item_list->first->info)
name = 0x8ca04758 "id",
(gdb) print *(Item_field*)(select_lex->item_list->first->next->info)
name = 0x8cb047f8 "name",
结构如下:
item_list:
|-->Item_field("id")
|-->Item_field("name")