文章
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,首先给出这条语句涉及到的语法节点(大体浏览下即可):
001
query:
002
END_OF_INPUT
003
{...}
004
|| verb_clause
005
{...}
006
| verb_clause END_OF_INPUT
007
{
008
/* Single query, not terminated. */
009
YYLIP->found_semicolon= NULL;
010
}
011
012
verb_clause:
013
statement
014
| begin
015
;
016
017
statement:
018
alter
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
071
select:
072
select_init
073
{
074
LEX *lex= Lex;
075
lex->sql_command= SQLCOM_SELECT;
076
}
077
;
078
079
select_init:
080
SELECT_SYM select_init2
081
|
'('
select_paren
')'
union_opt
082
;
083
084
085
select_init2:
086
select_part2
087
{
088
LEX *lex= Lex;
089
SELECT_LEX * sel= lex->current_select;
090
if
(lex->current_select->set_braces(0))
091
{
092
my_parse_error(ER(ER_SYNTAX_ERROR));
093
MYSQL_YYABORT;
094
}
095
if
(sel->linkage == UNION_TYPE &&
096
sel->master_unit()->first_select()->braces)
097
{
098
my_parse_error(ER(ER_SYNTAX_ERROR));
099
MYSQL_YYABORT;
100
}
101
}
102
union_clause
103
;
105
select_part2:
106
{
107
LEX *lex= Lex;
108
SELECT_LEX *sel= lex->current_select;
109
if
(sel->linkage != UNION_TYPE)
110
mysql_init_select(lex);
111
lex->current_select->parsing_place= SELECT_LIST;
112
}
113
select_options select_item_list
114
{
115
Select->parsing_place= NO_MATTER;
116
}
117
select_into select_lock_type
118
;