背景
一个最简单的select语句包含select子句、from子句、where子句等,这些子句都不包含子查询(subselect),也没有union操作。而复杂的select语句包含select子句、from子句、where子句(这些子查询可以y是最简单的select语句也可以y是复杂的select语句),同时select语句中可能包含union,即将数个select子句联合在一起。
MySQL解析器(lex+yacc)是如何解析上述复杂的SQL的呢?又是使用什么样的数据结构来完整的维护一个大的select中包含的subselect、union的d关系呢?本文希望通过介绍MySQL解析器中相关的数据结构及处理过程,解答上述两个问题。
主要数据结构及其之间关系
MySQL解析器中负责分析和存储一个select语句信息的数据结构是st_select_lex类(MySQL中同时将该类宏定义为SELECT_LEX),同时负责分析和存储union关系的数据结构是st_select_lex_unit(MySQL中同时将该类宏定义为SELECT_LEX_UNIT),而这两个类都继承于st_select_lex_node类。
对于SELECT_LEX类,它主要是存储一个select语句中select子句的返回列信息,from子句中的表信息,order by,group by子句的列信息等。对于本文所关心的问题,SELECT_LEX类使用继承于st_select_lex_node类的next指针存储和该select语句进行union操作的其他select语句对应的SELECT_LEX的地址,通过这个指针串成union链表。
例如:SQL1:select * from test1 where id=5 union select * from test1 where id=6;
对于SELECT_LEX_UNIT负责管理处于同一级的进行union操作的数个select子句对应的SELECT_LEX。SELECT_LEX_UNIT通过继承于st_select_lex_node类的slave指针存储属于这一级的进行union操作的第一个SELECT_LEX,而这一级别其他参与union操作的SELECT_LEX,可以通过next指针串成的链表依次找到。同时SELECT_LEX_UNIT类中还有一个成员变量fake_select_lex,它来保存整个union操作的order by,limit条件。
例如:
对于select子句,from子句,where子句中出现子查询(subselect)的情况,MySQL解析器会先建一个SELECT_LEX_UNIT,将此SELECT_LEX_UNIT挂在该子查询上一级select对应的SELECT_LEX下(即该SELECT_LEX的slave指针赋值为此SELECT_LEX_UNIT对应的地址),同时新建一个SELECT_LEX和这个子查询对应,将这个新建的SELECT_LEX挂在刚建的SELECT_LEX_UNIT下。
(未完待续)