(接上文)
下面以一个简单的SQL作为例子来讲解。
例如: Select * from tt where tt.id in (select id from tt1) union select * from tt1;
SQL在经过解析后的类间关系如下图:
MySQL解析器相关处理逻辑
MySQL解析器在分析到SQL存在union或者select子句,from子句,where子句中的subselect时,都会调用mysql_new_select函数维护上述所讲的数据结构,区别是union在调用mysql_new_select时传第二个参数move_down=0;subselect在调用mysql_new_select时传第二个参数move_down=1。
mysql_new_select函数具体解释如下:
Code:
bool mysql_new_select(LEX *lex, bool move_down)
{
SELECT_LEX *select_lex;
THD *thd= lex->thd;
DBUG_ENTER("mysql_new_select");
//为子查询新建一个SELECT_LEX即st_select_lex,这个st_select_lex可能对应遇到的select子句,from子句,
//where子句中的subselect或者union关系中的select子句; if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
DBUG_RETURN(1);
select_lex->select_number= ++thd->select_number;
select_lex->parent_lex= lex; /* Used in init_query. */
select_lex->init_query();
select_lex->init_select();
lex->nest_level++;
if (lex->nest_level > (int) MAX_SELECT_NESTING)
{
my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT,MYF(0),MAX_SELECT_NESTING);
DBUG_RETURN(1);
}
select_lex->nest_level= lex->nest_level;
if (thd->stmt_arena->is_stmt_prepare())
select_lex->uncacheable|= UNCACHEABLE_PREPARE;
//如果move_down=1,即是为select子句,from子句,where子句中的subselect创建相应数据结构时
if (move_down)
{
SELECT_LEX_UNIT *unit;
lex->subqueries= TRUE;
//新建一个SELECT_LEX_UNIT即st_select_lex_unit
if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
DBUG_RETURN(1);
unit->init_query();
unit->init_select();
unit->thd= thd;
//将此SELECT_LEX_UNIT挂在上一级select语句对应SELECT_LEX的下,即此SELECT_LEX的slave指针指向此SELECT_LEX_UNIT
unit->include_down(lex->current_select);
unit->link_next= 0;
unit->link_prev= 0;
unit->return_to= lex->current_select;
//同时将这个subselect对应的SELECT_LEX挂在刚建的这个SELECT_LEX_UNIT下,这里MySQL对于select子句,from子句,where子句
//中可能出现的subselect,都会先新建一个SELECT_LEX_UNIT挂在上一级select语句对应的SELECT_LEX下,
//同时建一个subselect对应的SELECT_LEX挂在SELECT_LEX_UNIT下。
//这样如果这个subselect的右边又出现了一个subselect和它进行union操作,可以将右边的这个subselect对应的
//SELECT_LEX放在上一级的SELECT_LEX_UNIT表达这个union关系。 select_lex->include_down(unit);
select_lex->context.outer_context= &select_lex->outer_select()->context;
}
//如果move_down=0;意味着对应处理的是union关系
else
{
if (lex->current_select->order_list.first && !lex->current_select->braces)
{
my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
DBUG_RETURN(1);
}
//将要处理这个新的参与union中的select子句对应的SELECT_LEX加入union链表中,union操作符左边这个select子句对应的
//SELECT_LEX已经在这个链表中 select_lex->include_neighbour(lex->current_select);
SELECT_LEX_UNIT *unit= select_lex->master_unit();
if (!unit->fake_select_lex && unit->add_fake_select_lex(lex->thd))
DBUG_RETURN(1);
select_lex->context.outer_context=
unit->first_select()->context.outer_context;
}
select_lex->master_unit()->global_parameters= select_lex;
select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
lex->current_select= select_lex;
select_lex->context.resolve_in_select_list= TRUE;
DBUG_RETURN(0);
}