mysql源码剖析–词法解析过程

  • 引言
  • 1 核心概念
  • 1.1 token
  • 1.2 my_lex_states
  • 2 主要流程


引言

一条sql语句传输到服务端后,必须先经过词法解析、语法分析生成语法树。一般程序的编译器大都采用flex完成词法解析、bison实现语法分析;mysql为了提高词法解析的效率和灵活性,独立编码实现了自己的词法解析模块。

1 核心概念

词法解析过程是通过扫描sql文本进行分词,并识别每个分词类型的过程。

1.1 token

token是分词类型编号值。每个关键字一个token值,此外,数字、字段值、表达式符号等都有相应的token值与之对应。
在mysql中,非一元符号的token分类定义在文件sql/sql_yacc.h的枚举yytokentype内。

1.2 my_lex_states

mysql词法解析采用状态机方式解析分词。刚开始设置为MY_LEX_START(也就是开始状态),然后直到扫描到一个非空格符(这里的空格不仅包括空格,还包括\t、\n等)后设置其下一个状态,并跳入下一个状态继续处理。。。最后扫描到一个完整的分词结束。
my_lex_states就是每扫描到一个字符,其对应的下一个状态类型。定义在include/my_ctype.h中,其初始化在文件mysys/charset.c的函数init_state_maps中。

2 主要流程

mysql的词法解析在文件sql/sql_lex.cc的函数MYSQLlex中:

  • 首先,从线程上下文THD中获取Lex_input_stream指针,通过名称可以发现该类是扫描sql命令的流;
  • 如果Lex_input_stream中已经解析好了下一个token,则直接返回;否则下一步。
  • 调用函数lex_one_token扫描下一个分词,该函数是词法解析的核心;
  • 若lex_one_token解析出的token是WITH分词,则继续调用函数lex_one_token扫描下一个分词;若下一个分词是CUBE_SYM、则返回WITH_CUBE_SYM,若是ROLLUP_SYM、则返回WITH_ROLLUP_SYM,若是其他类型、则返回WITH并将第二个分词缓存到Lex_input_stream中。
  • 对于第一次调用lex_one_token解析出的token不是WITH分词,则直接返回。

lex_one_token函数也定义在文件sql/sql_lex.cc中

  • 首先,通过THD::charset()获取CHARSET_INFO指针,然后获取state_map和ident_map。
    state_map是词法扫描到的字符与对应状态的索引;ident_map是字符对应状态为MY_LEX_IDENT(关键字分词)或MY_LEX_NUMBER_IDENT(数字开头的分词)的位图;
  • 然后,进入for循环运行词法解析状态机逻辑;这一块是词法解析的核心。
    一般默认开始进入MY_LEX_START状态,在该状态下,当扫描到第一个非MY_LEX_SKIP字符,然后从state_map获取对应字符的状态、将其设置为下一状态;然后继续下一轮循环。。。