MySQL內核源碼解讀-SQL解析一
1. SQL總體執行流程圖
通過上面圖,可以從全局上了解SQL語句執行流程以及與其他模塊交互
1.1 SQL查詢執行流程
2. 語法解析
2.1 編程語言知識回顧
在介紹具體的MySQL數據庫解析SQL之前,先來回歸一下編程語言的知識點
- 形式語言(Formal language)
形式語言是用精確的數學或機器可處理的公式定義的語言,個人理解形式語言就是符號化的語言,比如編程語言(C C++ JAVA PYTHON),都是定義一組符號來描述映射人的思維邏輯的,符號化的語言的好處就是能夠準確表達,不會產生二義性. - 文法(grammar)
當我們要描述一種語言時,需要給出這種語言的所有句子,當句子的數目是有限可數時,就要都列出來;當句子是一個無窮集,也就是無限不可數時,就要給出可以表示它們的結構的描述方法或者說,句子的組成規則。這種規則就是文法。即從形式上用於描述和規定結構的稱為文法(或者說語法), 也可以理解為指怎麽由一堆符號組成一個有含義的句子的規則和協議 - 上下文無關文法(context-free grammar)(數學描述)
一個四元數組G=(VN,VT,S,P):
VN:非空有限的非終結符集合VT:非空有限的終結符集
S:開始符號P:產生式集合
其中,VN∩VT=?,S∈VN
P中產生式一般形式為A→α|β,其中A∈VN,α,β∈(VN∪VT)*
大寫字母表示非終結符,小寫字母表示終結符,α、β、γ等代表由 終結符和非終結符號的並集的閉包 中的元素 組成的符號串
上下文無關文法取名為“上下文無關”的原因就是因為字符A總可以被字串α或β自由替換,而無需考慮字符A出現的上下文 - 終結符(terminal symbol )
終結符是一個形式語言的基本符號。就是說,它們能在一個形式語法的推導規則的輸入或輸出字符串存在,而且它們不能被分解成更小的單位。可以理解為產生式推導到什麽時候停止呢,推導到終止符為止. - 非終結符(nonterminal symbol)
非終結符是可以被取代的符號。一個形式文法中必須有一個起始符號;這個起始符號屬於非終結符的集合。在上下文無關文法中,每個推導規則的左邊只能有一個非終結符而不能有兩個以上的非終結符或終結符。 - 巴科斯範式(BNF: Backus-Naur Form)
以美國人巴科斯(Backus)和丹麥人諾爾(Naur)的名字命名的一種形式化的語法表示方法,用來描述語法的一種形式體系,是一種典型的元語言。又稱巴科斯-諾爾形式(Backus-Naur form)。它不僅能嚴格地表示語法規則,而且所描述的語法是與上下文無關的。它具有語法簡單,表示明確,便於語法分析和編譯的特點。
2.2 概念與bison
2.1章節說明的概念跟bison又是一種什麽關系呢?
bison是屬於 GNU 項目的一個語法分析器生成器。
bison能夠將上下文無文法解釋成語法分析表,由於兼容yacc,而yacc是BNF進行描述文法規則的, 所以可以理解為bison能夠解析以BNF描述上下文無關文法的語法分析器生成器.
2.3 MySQL與bison
MySQL使用bison作為其解析SQL語句的語法分析器.
2.4 SQL解析相關文件及關聯
(1) 相關文件
SQL詞法解析文件:
sql/sql_lex.h、sql/lex_token.h、sql/lex.h、sql/lex_symbol.h
sql/gen_lex_token.cc、sql/sql_lex.cc
SQL語法解析文件:
sql/sql_yacc.yy、sql/sql_yacc.cc、sql/sql_yacc.h
SQL語句的hint語法解析文件:
sql/sql_hints.yy、sql/sql_hints.yy.cc
(2) 語法解析
3. sql/sql_yacc.yy
3.1 sql_yacc.yy描述
sql_yacc.cc規定了SQL語句語法規則,定義了SQL語句的關鍵字.
3.2 sql_yacc.yy文件結構
%{
Prologue
%}Bison declarations
%%
Grammar rules
%%Epilogue
- Prologue部分包括宏定義和在語法規則動作中使用的函數和變量的聲明. 這些將復制到分析器文件的開頭以便先於yyparse的定義. 你可以使用
#include‘來從頭文件獲取聲明. 如果你不需要任何的C聲明, 可以省略這個部分的括號分隔符
%{‘和`%}‘, 這部分被BISON原封不動地復制到輸出的.C文件中 - Bison declatations部分包含了定義終結符和非終結符的聲明,優先級等等
- Grammar Rules部分包含了一個或多個Bison語法規則, 在這裏至少應該有一個語法規則,並且第一個%%, 絕對不能省略,解釋它在文件的最開頭.
- 就像Prologue部分被復制到開頭一樣,Epilogue部分被逐字地復制到分析器文件的結尾. 如果你想放一些代碼卻沒必要放在yyparse的定義之前,這裏是最方便的地方. 如果最後一部分為空,你可以省略分隔它的分隔符%%.
3.2 sql_yacc.yy文件解析
3.2.1 Prologue部分
該部分包含了C語言的頭文件,宏定義,該部分主要聲明和定義了2個關鍵函數,如下:
int yylex(void yylval, void yythd);詞法解析函數的聲明
void MYSQLerror(YYLTYPE , THD thd, const char *s);語法分析錯誤函數的定義。
3.2.2 Bison declatations部分
本部分與prologue部分使用 %% 進行分隔
3.2.3 Grammar Rules部分
本部分與Bison declatations部分,使用 %% 進行分隔
例子分析:
Bison產生式: result: components…;
下面的例子就是一個產生式
query是產生式的左端, 冒號後面是產生式的右端, | 代表或的意思, {}當query產生式推出右端情況的時候所執行的動作,一個產生式結束要是 ;
其中, query verb_clause 都是非終止符, END_OF_INPUT 是終止符, 也就是說產生式推導到終止符就停止推導.
即query->END_OF_INPUT | verb_clause | verb_clause END_OF_INPUT
query:
- END_OF_INPUT
- { THD *thd= YYTHD;
- if (!thd->bootstrap &&!thd->m_parser_state->has_comment())
- {
- my_message(ER_EMPTY_QUERY, ER(ER_EMPTY_QUERY), MYF(0));
- MYSQL_YYABORT;
- }
- thd->lex->sql_command= SQLCOM_EMPTY_QUERY;
- YYLIP->found_semicolon= NULL;
- }
- | verb_clause
- { Lex_input_stream *lip = YYLIP;
- if (YYTHD->get_protocol()->has_client_capability(CLIENT_MULTI_QUERIE S)&& lip->multi_statements && !lip->eof())
- {
- lip->next_state= MY_LEX_END;
- lip->found_semicolon= lip->get_ptr();
- }
- else
- { lip->found_semicolon= NULL;}
- }
- ‘;‘
- opt_end_of_input
- |verb_clause END_OF_INPUT
- {YYLIP->found_semicolon= NULL;}
參考資料
- 《lex與yacc》(第二版)
- 《flex與bison》(第二版)
- Bison操作手冊
http://www.gnu.org/software/bison/manual/bison.html
本文由京東商城數據庫技術部傅誌宇提供。
MySQL內核源碼解讀-SQL解析一