MySQL解析器源码分析--对select语句中子查询处理逻辑的分析(二)

  1. 云栖社区>
  2. 博客>
  3. 正文

MySQL解析器源码分析--对select语句中子查询处理逻辑的分析(二)

技术小美 2017-11-08 16:26:00 浏览550
展开阅读全文

(接上文)

下面以一个简单的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); }
【本文首发于:百度运维空间http://hi.baidu.com/ops_bd/blog/item/52e0e13fce2cdc3fb9998f4c.html
关注百度技术沙龙










本文转自百度技术51CTO博客,原文链接:http://blog.51cto.com/baidutech/748849,如需转载请自行联系原作者

网友评论

登录后评论
0/500
评论
技术小美
+ 关注