Article
Mysql源码学习——打造专属语法总结
2011/8/9 13:30:47
接触过SQL语句的人都会看过这家或者那家的SQL手册,其语法标准应该是从SQL92开始吧,在看SQL92标准的时候,你会发现里面定义的都是一些巴科斯范式(BNF),就是一种语法定义的标准。不管是牛X哄哄的ORACLE,还是不幸被其收购的Mysql,都会遵循里面的标准语法,当然一些扩展的语法除外,比如今天我们就会扩展一个简单的语法^-^。
OK,大家知道了SQL语法的来源,那么如何进行语法解析呢?YACC!!(Yet Another Compiler Compiler),它的书写方式便是BNF,语法解析的利器。YACC接收来自词法分析阶段分解出来的token,然后去匹配那些BNF。今天哥就来揭开它的面纱。(关于YACC的基本使用方法,大家可以看我上一篇中提到IBM的链接,一定要看懂那个先)
继续上一节的语句SELECT @@VERSION_COMMET,为了简单,这里省去后缀limit 1。Mysql的语法文件是sql_yacc.yy,首先给出这条语句涉及到的语法节点(大体浏览下即可):
001query:
002END_OF_INPUT
003{...}
004|| verb_clause
005{...}
006| verb_clause END_OF_INPUT
007{
008/* Single query, not terminated. */
009YYLIP->found_semicolon= NULL;
010}
011
012verb_clause:
013statement
014| begin
015;
016
017statement:
018alter
019| analyze
020| backup
021| binlog_base64_event
022| call
023| change
024| check
025| checksum
026| commit
027| create
028| deallocate
029|delete
030| describe
031|do
032| drop
033| execute
034| flush
035| grant
036| handler
037| help
038| insert
039| install
040| kill
041| load
042| lock
043| optimize
044| keycache
045| partition_entry
046| preload
047| prepare
048| purge
049| release
050|rename
051| repair
052| replace
053| reset
054| restore
055| revoke
056| rollback
057| savepoint
058| select
059| set
060| show
061| slave
062| start
063| truncate
064| uninstall
065| unlock
066| update
067| use
068| xa
069;
070
071select:
072select_init
073{
074LEX *lex= Lex;
075lex->sql_command= SQLCOM_SELECT;
076}
077;
078
079select_init:
080SELECT_SYM select_init2
081|'('select_paren')'union_opt
082;
083
084
085select_init2:
086select_part2
087{
088LEX *lex= Lex;
089SELECT_LEX * sel= lex->current_select;
090if(lex->current_select->set_braces(0))
091{
092my_parse_error(ER(ER_SYNTAX_ERROR));
093MYSQL_YYABORT;
094}
095if(sel->linkage == UNION_TYPE &&
096sel->master_unit()->first_select()->braces)
097{
098my_parse_error(ER(ER_SYNTAX_ERROR));
099MYSQL_YYABORT;
100}
101}
102union_clause
103;
105select_part2:
106{
107LEX *lex= Lex;
108SELECT_LEX *sel= lex->current_select;
109if(sel->linkage != UNION_TYPE)
110mysql_init_select(lex);
111lex->current_select->parsing_place= SELECT_LIST;
112}
113select_options select_item_list
114{
115Select->parsing_place= NO_MATTER;
116}
117select_into select_lock_type
118;