<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet href='http://feed.feedsky.com/styles/feedsky2.xsl' type='text/xsl' ?><!--这是一个由Feedsy提供技术支持的Feed，为了提高读者阅读的体验，以及满足用户美化自己Feed的需要，我们设计了多种精美的Feed模板，提供给大家选择，所有最终呈现出来的样式，皆由用户自愿选择使用，未经许可，任何团体和个人，请不要擅自修改样式或者盗用，这是对于用户选择权的尊重。--><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fs="http://www.feedsky.com/namespace/feed" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link href="http://feed.feedsky.com/ourmysql" type="application/rss+xml" rel="self"></atom:link><fs:self_link href="http://feed.feedsky.com/ourmysql" type="application/rss+xml"></fs:self_link><lastBuildDate>Mon, 26 Mar 2012 14:55:48 GMT</lastBuildDate><title>OurMySQL</title><description>我们致力于一个MySQL知识的分享网站</description><image><url>http://www.feedsky.com/feed/ourmysql/sc/gif</url><title>OurMySQL</title><link>http://ourmysql.com</link></image><link>http://ourmysql.com</link><sy:updatePeriod>hourly</sy:updatePeriod><sy:updateFrequency>1</sy:updateFrequency><language>en</language><pubDate>Mon, 26 Mar 2012 14:55:48 GMT</pubDate><item><title>MYSQL的DECIMAL和NUMERIC类型</title><link>http://ourmysql.com/archives/1115</link><content:encoded>&lt;p&gt;MYSQL, DECIMAL和NUMERIC类型 说明:&lt;/p&gt;
&lt;div id=&quot;_mcePaste&quot;&gt;DECIMAL和NUMERIC类型在MySQL中视为相同的类型。它们用于保存必须为确切精度的值，例如货币数据。&lt;/div&gt;
&lt;div id=&quot;_mcePaste&quot;&gt;当声明该类型的列时，可以(并且通常要)指定精度和标度；例如：&lt;/div&gt;
&lt;div id=&quot;_mcePaste&quot;&gt;salary &lt;a href=&quot;http://ourmysql.com/archives/tag/decimal&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 DECIMAL 下的日志&quot;&gt;DECIMAL&lt;/a&gt;(5,2)&lt;/div&gt;
&lt;div id=&quot;_mcePaste&quot;&gt;在该例子中，5是精度，2是标度。精度表示保存值的主要位数，标度表示小数点后面可以保存的位数。&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div id=&quot;_mcePaste&quot;&gt;在MySQL 5.1中以二进制格式保存DECIMAL和NUMERIC值。&lt;/div&gt;
&lt;div id=&quot;_mcePaste&quot;&gt;标准SQL要求salary列能够用5位整数位和两位小数保存任何值。因此，在这种情况下可以保存在salary列&lt;/div&gt;
&lt;div id=&quot;_mcePaste&quot;&gt;的值的范围是从-999.99到999.99。&lt;/div&gt;
&lt;div id=&quot;_mcePaste&quot;&gt;在标准SQL中，语法DECIMAL(M)等价于DECIMAL(M,0)。同样，语法DECIMAL等价于DECIMAL(M,0)，可以通过&lt;/div&gt;
&lt;div id=&quot;_mcePaste&quot;&gt;计算确定M的值。在MySQL 5.1中支持DECIMAL和NUMERIC数据类型的变量形式。M默认值是10。&lt;/div&gt;
&lt;div id=&quot;_mcePaste&quot;&gt;DECIMAL或NUMERIC的最大位数是65，但具体的DECIMAL或NUMERIC列的实际范围受具体列的精度或标度约束&lt;/div&gt;
&lt;div id=&quot;_mcePaste&quot;&gt;。如果此类列分配的值小数点后面的位数超过指定的标度允许的范围，值被转换为该标度。(具体操作与&lt;/div&gt;
&lt;div id=&quot;_mcePaste&quot;&gt;操作系统有关，但一般结果均被截取到允许的位数）。&lt;/div&gt;
&lt;p&gt;MYSQL, DECIMAL和NUMERIC类型 说明:&lt;br /&gt;
DECIMAL和NUMERIC类型在MySQL中视为相同的类型。它们用于保存必须为确切精度的值，例如货币数据。&lt;br /&gt;
当声明该类型的列时，可以(并且通常要)指定精度和标度；例如：&lt;br /&gt;
salary DECIMAL(5,2)在该例子中，5是精度，2是标度。精度表示保存值的主要位数，标度表示小数点后面可以保存的位数。&lt;br /&gt;
在MySQL 5.1中以二进制格式保存DECIMAL和NUMERIC值。&lt;br /&gt;
标准SQL要求salary列能够用5位整数位和两位小数保存任何值。因此，在这种情况下可以保存在salary列&lt;br /&gt;
的值的范围是从-999.99到999.99。&lt;br /&gt;
在标准SQL中，语法DECIMAL(M)等价于DECIMAL(M,0)。同样，语法DECIMAL等价于DECIMAL(M,0)，可以通过&lt;br /&gt;
计算确定M的值。在MySQL 5.1中支持DECIMAL和NUMERIC数据类型的变量形式。M默认值是10。&lt;br /&gt;
DECIMAL或NUMERIC的最大位数是65，但具体的DECIMAL或NUMERIC列的实际范围受具体列的精度或标度约束&lt;br /&gt;
。如果此类列分配的值小数点后面的位数超过指定的标度允许的范围，值被转换为该标度。(具体操作与&lt;br /&gt;
操作系统有关，但一般结果均被截取到允许的位数）。&lt;/p&gt;
&lt;h3  class=&quot;related_post_title&quot;&gt;相关文章&lt;/h3&gt;&lt;ul class=&quot;related_post&quot;&gt;&lt;li&gt;目前没有相关的文章&lt;/li&gt;&lt;/ul&gt;
	标签：&lt;a href=&quot;http://ourmysql.com/archives/tag/decimal&quot; title=&quot;DECIMAL&quot; rel=&quot;tag&quot;&gt;DECIMAL&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/category/basic&quot; title=&quot;MySQL基础知识&quot; rel=&quot;tag&quot;&gt;MySQL基础知识&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/numeric&quot; title=&quot;NUMERIC&quot; rel=&quot;tag&quot;&gt;NUMERIC&lt;/a&gt;&lt;br /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/620934119/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1115&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://ourmysql.com/archives/1115/feed</wfw:commentRss><slash:comments>0</slash:comments><description>MYSQL, DECIMAL和NUMERIC类型 说明:
DECIMAL和NUMERIC类型在MySQL中视为相同的类型。它们用于保存必须为确切精度的值，例如货币数据。
当声明该类型的列时，可以(并且通常要)指定精度和标度；&lt;img src=&quot;http://www1.feedsky.com/t1/620934119/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1115&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>NUMERIC</category><category>MySQL基础知识</category><category>DECIMAL</category><pubDate>Mon, 26 Mar 2012 22:55:48 +0800</pubDate><author>OurMySQL</author><comments>http://ourmysql.com/archives/1115#comments</comments><guid isPermaLink="false">http://ourmysql.com/?p=1115</guid><dc:creator>OurMySQL</dc:creator><fs:srclink>http://ourmysql.com/archives/1115</fs:srclink><fs:srcfeed>http://www.ourmysql.com/feed</fs:srcfeed><fs:itemid>feedsky/ourmysql/~7195843/620934119/5270018</fs:itemid></item><item><title>mysql hash 破解提权</title><link>http://ourmysql.com/archives/1112</link><content:encoded>&lt;p&gt;mssql的hash保存在表master.dbo.sysxlogins中，用&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;select name,password from master.dbo.sysxlogins&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;可以提取用户hash&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
0x01004E04BE46023057E323AF27269E5B7DDCA140C98D225BDD3D06E8EFE8CFAEC02985B27B38059FA3B18349612B&lt;br /&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;分解：&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;常量部分：0×0100&lt;br /&gt;
Salt部分：4E04BE46&lt;br /&gt;
混合密文：023057E323AF27269E5B7DDCA140C98D225BDD3D&lt;br /&gt;
大写字母密文：06E8EFE8CFAEC02985B27B38059FA3B18349612B 后40位&lt;/p&gt;
&lt;p&gt;有了HASH就可以破解了，用到的工具是CAIN。&lt;/p&gt;
&lt;p&gt;转到CAIN的破解功能那里，添加一个待破解的MSSQL &lt;a href=&quot;http://ourmysql.com/archives/tag/hash&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 Hash 下的日志&quot;&gt;HASH&lt;/a&gt;&lt;br /&gt;
有三个需要写的文本框。&lt;/p&gt;
&lt;p&gt;将salt ，混合密文 跟大写字母密文填入，就可以破解了。&lt;/p&gt;
&lt;div&gt;
&lt;p&gt;mysql的用户名密码保存在mysql库user表中，找到MySQL\data\mysql\目录下的 user.MYD user.MYI user.frm 三个文件，拷贝到自己的mysql数据库目录下，就可以查看用户的hash了。&lt;br /&gt;
用sql语句提取hash则如下：&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;use mysql;&lt;br /&gt;
select user,password from user;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;得到hash：&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
test:*085D85329E1557C869A120C9157315A07D51E8A7&lt;br /&gt;
ogame:*085D85329E1557C869A120C9157315A07D51E8A7&lt;br /&gt;
iii6_com:*085D85329E1557C869A120C9157315A07D51E8A7&lt;br /&gt;
root:*5D0B157F0A3BB4DB1A0092B4F270FBDA486EC6EB&lt;br /&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;冒号左边是用户，右边是HASH&lt;br /&gt;
HASH值开头带”*”号的是MYSQL5的HASH&lt;br /&gt;
不带*号的是旧版MYSQL的HASH(也就是MYSQL323)&lt;/p&gt;
&lt;p&gt;破解：&lt;br /&gt;
用passwordspro或者cain的破解器可以破解。&lt;/p&gt;
&lt;/div&gt;
&lt;h3  class=&quot;related_post_title&quot;&gt;相关文章&lt;/h3&gt;&lt;ul class=&quot;related_post&quot;&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1107&quot; title=&quot;Mysql源码学习——没那么简单的Hash&quot;&gt;Mysql源码学习——没那么简单的Hash&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2009-07-15 -- &lt;a href=&quot;http://ourmysql.com/archives/623&quot; title=&quot;memory型表支持Hash索引&quot;&gt;memory型表支持Hash索引&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2009-04-08 -- &lt;a href=&quot;http://ourmysql.com/archives/510&quot; title=&quot;有趣的bloom过滤器&quot;&gt;有趣的bloom过滤器&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
	标签：&lt;a href=&quot;http://ourmysql.com/archives/tag/hash&quot; title=&quot;Hash&quot; rel=&quot;tag&quot;&gt;Hash&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/category/advanced&quot; title=&quot;MySQL高级应用&quot; rel=&quot;tag&quot;&gt;MySQL高级应用&lt;/a&gt;&lt;br /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/620934121/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1112&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://ourmysql.com/archives/1112/feed</wfw:commentRss><slash:comments>0</slash:comments><description>mssql的hash保存在表master.dbo.sysxlogins中，用select name,password from master.dbo.sysxlogins可以提取用户hash&lt;img src=&quot;http://www1.feedsky.com/t1/620934121/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1112&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>MySQL高级应用</category><category>Hash</category><pubDate>Mon, 26 Mar 2012 22:54:07 +0800</pubDate><author>OurMySQL</author><comments>http://ourmysql.com/archives/1112#comments</comments><guid isPermaLink="false">http://ourmysql.com/?p=1112</guid><dc:creator>OurMySQL</dc:creator><fs:srclink>http://ourmysql.com/archives/1112</fs:srclink><fs:srcfeed>http://www.ourmysql.com/feed</fs:srcfeed><fs:itemid>feedsky/ourmysql/~7195843/620934121/5270018</fs:itemid></item><item><title>mysql 数据库查询随机数量条目的效率问题及解决办法</title><link>http://ourmysql.com/archives/1110</link><content:encoded>&lt;p&gt;最近由于需要大概研究了一下MYSQL的随机抽取实现方法。举个例子，要从tablename表中随机提取一条记录，大家一般的写法就是：SELECT * FROM tablename ORDER BY RAND() LIMIT 1。&lt;/p&gt;
&lt;p&gt;但是，后来我查了一下MYSQL的官方手册，里面针对RAND()的提示大概意思就是，在ORDER BY从句里面不能使用RAND()函数，因为这样会导致数据列被多次扫描。但是在MYSQL 3.23版本中，仍然可以通过ORDER BY RAND()来实现随机。&lt;/p&gt;
&lt;p&gt;但是真正测试一下才发现这样效率非常低。一个15万余条的库，查询5条数据，居然要8秒以上。查看官方手册，也说rand()放在ORDER BY 子句中会被执行多次，自然效率及很低。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;搜索Google，网上基本上都是查询max(id) * rand()来随机获取数据。&lt;br /&gt;
SELECT * FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM `table`)) AS id) AS t2 WHERE t1.id &amp;gt;= t2.id ORDER BY t1.id ASC LIMIT 5;&lt;/p&gt;
&lt;p&gt;但是这样会产生连续的5条记录。解决办法只能是每次查询一条，查询5次。即便如此也值得，因为15万条的表，查询只需要0.01秒不到。&lt;/p&gt;
&lt;p&gt;下面的语句采用的是JOIN，mysql的论坛上有人使用&lt;/p&gt;
&lt;p&gt;SELECT * FROM `table` WHERE id &amp;gt;= (SELECT FLOOR( MAX(id) * RAND()) FROM `table` ) ORDER BY id LIMIT 1;&lt;/p&gt;
&lt;p&gt;我测试了一下，需要0.5秒，速度也不错，但是跟上面的语句还是有很大差距。总觉有什么地方不正常。&lt;/p&gt;
&lt;p&gt;于是我把语句改写了一下。&lt;br /&gt;
SELECT * FROM `table`&lt;br /&gt;
WHERE id &amp;gt;= (SELECT floor(RAND() * (SELECT MAX(id) FROM `table`)))&lt;br /&gt;
ORDER BY id LIMIT 1;&lt;/p&gt;
&lt;p&gt;这下，效率又提高了，查询时间只有0.01秒&lt;/p&gt;
&lt;p&gt;最后，再把语句完善一下，加上MIN(id)的判断。我在最开始测试的时候，就是因为没有加上MIN(id)的判断，结果有一半的时间总是查询到表中的前面几行。&lt;br /&gt;
完整查询语句是：&lt;br /&gt;
SELECT * FROM `table`&lt;br /&gt;
WHERE id &amp;gt;= (SELECT floor( RAND() * ((SELECT MAX(id) FROM `table`)-(SELECT MIN(id) FROM `table`)) + (SELECT MIN(id) FROM `table`)))&lt;br /&gt;
ORDER BY id LIMIT 1;&lt;/p&gt;
&lt;p&gt;SELECT *&lt;br /&gt;
FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM `table`)-(SELECT MIN(id) FROM `table`))+(SELECT MIN(id) FROM `table`)) AS id) AS t2&lt;br /&gt;
WHERE t1.id &amp;gt;= t2.id&lt;br /&gt;
ORDER BY t1.id LIMIT 1;&lt;/p&gt;
&lt;p&gt;最后在php中对这两个语句进行分别查询10次，&lt;br /&gt;
前者花费时间 0.147433 秒&lt;br /&gt;
后者花费时间 0.015130 秒&lt;br /&gt;
看来采用JOIN的语法比直接在WHERE中使用函数效率还要高很多。&lt;/p&gt;
&lt;h3  class=&quot;related_post_title&quot;&gt;相关文章&lt;/h3&gt;&lt;ul class=&quot;related_post&quot;&gt;&lt;li&gt;2009-04-14 -- &lt;a href=&quot;http://ourmysql.com/archives/524&quot; title=&quot;MySql 随机读取数据&quot;&gt;MySql 随机读取数据&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
	标签：&lt;a href=&quot;http://ourmysql.com/archives/category/optimize&quot; title=&quot;MySQL优化设计&quot; rel=&quot;tag&quot;&gt;MySQL优化设计&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/%e9%9a%8f%e6%9c%ba&quot; title=&quot;随机&quot; rel=&quot;tag&quot;&gt;随机&lt;/a&gt;&lt;br /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/620934122/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1110&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://ourmysql.com/archives/1110/feed</wfw:commentRss><slash:comments>0</slash:comments><description>最近由于需要大概研究了一下MYSQL的随机抽取实现方法。举个例子，要从tablename表中随机提取一条记录，大家一般的写法就是：SELECT * FROM tablename ORDER BY RAND() LIMIT 1。
但是，后来我查了一下MYSQL的官方手册，里面针对RAND()的提示大概意思就是，在ORDER BY从句里面不能使用RAND()函数，因为这样会导致数据列被多次扫描。但是在MYSQL 3.23版本中，仍然可以通过ORDER BY RAND()来实现随机。
但是真正测试一下才发现这样效率非常低。一个15万余条的库，查询5条数据，居然要8秒以上。查看官方手册，也说rand()放在ORDER BY 子句中会被执行多次，自然效率及很低。&lt;img src=&quot;http://www1.feedsky.com/t1/620934122/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1110&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>MySQL优化设计</category><category>随机</category><pubDate>Mon, 26 Mar 2012 22:51:57 +0800</pubDate><author>OurMySQL</author><comments>http://ourmysql.com/archives/1110#comments</comments><guid isPermaLink="false">http://ourmysql.com/?p=1110</guid><dc:creator>OurMySQL</dc:creator><fs:srclink>http://ourmysql.com/archives/1110</fs:srclink><fs:srcfeed>http://www.ourmysql.com/feed</fs:srcfeed><fs:itemid>feedsky/ourmysql/~7195843/620934122/5270018</fs:itemid></item><item><title>Mysql源码学习——没那么简单的Hash</title><link>http://ourmysql.com/archives/1107</link><content:encoded>&lt;div id=&quot;cnblogs_post_body&quot;&gt;
&lt;blockquote&gt;
&lt;p align=&quot;justify&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;a href=&quot;http://ourmysql.com/archives/tag/hash&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 Hash 下的日志&quot;&gt;Hash&lt;/a&gt; 链表的应用比较常见，其目的就是为了将不同的值映射到不同的位置，查找的时候直接找到相应的位置，而不需要传统的顺序遍历或是二分查找，从而达到减少查询 时间的目的。常规的hash是预定义一定的桶(bucket)，规定一个hash函数，然后进行散列。然而Mysql中的hash没有固定的 bucket，&lt;span style=&quot;color: #ff00ff;&quot;&gt;hash函数也是动态变化的&lt;/span&gt;，本文就进行非深入介绍。&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align=&quot;justify&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h1&gt;&lt;strong&gt;基本结构体 &lt;/strong&gt;&lt;/h1&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style=&quot;font-size: medium;&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Hash的结构体定义以及相关的函数接口定义在&lt;em&gt;&lt;strong&gt;include/hash.h&lt;/strong&gt;&lt;/em&gt;和&lt;em&gt;&lt;strong&gt;mysys/hash.c&lt;/strong&gt;&lt;/em&gt;两个文件中。下面是HASH结构体的定义。&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_429494&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;typedef&lt;/code&gt; &lt;code&gt;struct&lt;/code&gt; &lt;code&gt;st_hash {&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;size_t&lt;/code&gt; &lt;code&gt;key_offset,key_length;     &lt;/code&gt;&lt;code&gt;/* Length of key if const length */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;size_t&lt;/code&gt; &lt;code&gt;blength;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;ulong records;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;uint flags;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;DYNAMIC_ARRAY array;              &lt;/code&gt;&lt;code&gt;/* Place for hash_keys */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;my_hash_get_key get_key;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;void&lt;/code&gt; &lt;code&gt;(*&lt;/code&gt;&lt;code&gt;free&lt;/code&gt;&lt;code&gt;)(&lt;/code&gt;&lt;code&gt;void&lt;/code&gt; &lt;code&gt;*);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;CHARSET_INFO *charset;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;} HASH;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;table width=&quot;400&quot; border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;成员名&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;说明&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;key_offset&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;hash时key的offset，在不指定hash函数的情况下有意义&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;key_length&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;key的长度，用于计算key值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;&lt;span style=&quot;color: #ff00ff;&quot;&gt;blength&lt;/span&gt;&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;&lt;span style=&quot;color: #ff00ff;&quot;&gt;非常重要的辅助结构，初始为1，动态变化，用于hash函数计算，这里理解为bucket length（其实不是真实的bucket数）&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;records&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;实际的记录数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;flags&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;是否允许存在相同的元素，取值为HASH_UNIQUE(1)或者0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;array&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;存储元素的数组&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;get_key&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;用户定义的hash函数，可以为NULL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;free&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;析构函数，可以为NULL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;charset&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;字符集&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_669241&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;&amp;lt;font size=&lt;/code&gt;&lt;code&gt;&quot;4&quot;&lt;/code&gt;&lt;code&gt;&amp;gt; &amp;lt;/font&amp;gt;&amp;lt;font size=&lt;/code&gt;&lt;code&gt;&quot;3&quot;&lt;/code&gt;&lt;code&gt;&amp;gt;HASH 结构体里面包含了一个动态数组结构体DYNAMIC_ARRAY，这里就一并介绍了。其定义 在&amp;lt;em&amp;gt;&amp;lt;strong&amp;gt;include/my_sys.h&amp;lt;/strong&amp;gt;&amp;lt;/em&amp;gt; 中。&amp;lt;/font&amp;gt;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_649863&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;typedef&lt;/code&gt; &lt;code&gt;struct&lt;/code&gt; &lt;code&gt;st_dynamic_array&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;uchar *buffer;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;uint elements,max_element;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;uint alloc_increment;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;uint size_of_element;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;} DYNAMIC_ARRAY;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;table width=&quot;400&quot; border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;成员名&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;说明&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;buffer&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;一块连续的地址空间，用于存储数据，可以看成一个数组空间&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;elements&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;元素个数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;max_element&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;元素个数上限&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;alloc_increment&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;当元素达到上限时，即buffer满时，按照alloc_increment进行扩展&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;size_of_element&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;每个元素的长度&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h1&gt;&lt;strong&gt;初始化函数&lt;/strong&gt;&lt;/h1&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Hash初始化函数对外提供两个，my_hash_init和my_hash_init2，其区别即是否定义了growth_size（用于设置DYNAMIC_ARRAY的alloc_increment）。代码在&lt;strong&gt;&lt;em&gt;mysys/hash.c&lt;/em&gt;&lt;/strong&gt;中。&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_248302&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;#define my_hash_init(A,B,C,D,E,F,G,H) \&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;_my_hash_init(A,0,B,C,D,E,F,G,H)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;#define my_hash_init2(A,B,C,D,E,F,G,H,I) \&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;_my_hash_init(A,B,C,D,E,F,G,H,I)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;/**&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;@brief Initialize the hash&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;@details&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;Initialize the hash, by defining and giving valid values for&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;its elements. The failure to allocate memory for the&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;hash-&amp;gt;array element will not result in a fatal failure. The&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;dynamic array that is part of the hash will allocate memory&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;as required during insertion.&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;@param[in,out] hash         The hash that is initialized&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;@param[in]     charset      The charater set information&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;@param[in]     size         The hash size&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;@param[in]     key_offest   The key offset for the hash&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;@param[in]     key_length   The length of the key used in&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                              &lt;/code&gt;&lt;code&gt;the hash&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;@param[in]     get_key      get the key for the hash&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;@param[in]     free_element pointer to the function that&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                              &lt;/code&gt;&lt;code&gt;does cleanup&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;@return        inidicates success or failure of initialization&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;@retval 0 success&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;@retval 1 failure&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;*/&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;my_bool&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;_my_hash_init(HASH *hash, uint growth_size, CHARSET_INFO *charset,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;ulong size, &lt;/code&gt;&lt;code&gt;size_t&lt;/code&gt; &lt;code&gt;key_offset, &lt;/code&gt;&lt;code&gt;size_t&lt;/code&gt; &lt;code&gt;key_length,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;my_hash_get_key get_key,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;void&lt;/code&gt; &lt;code&gt;(*free_element)(&lt;/code&gt;&lt;code&gt;void&lt;/code&gt;&lt;code&gt;*), uint flags)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;&lt;a href=&quot;http://ourmysql.com/archives/tag/dbug&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 DBUG 下的日志&quot;&gt;DBUG&lt;/a&gt;_ENTER(&lt;/code&gt;&lt;code&gt;&quot;my_hash_init&quot;&lt;/code&gt;&lt;code&gt;);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;DBUG_PRINT(&lt;/code&gt;&lt;code&gt;&quot;enter&quot;&lt;/code&gt;&lt;code&gt;,(&lt;/code&gt;&lt;code&gt;&quot;hash: 0x%lx  size: %u&quot;&lt;/code&gt;&lt;code&gt;, (&lt;/code&gt;&lt;code&gt;long&lt;/code&gt;&lt;code&gt;) hash, (uint) size));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;hash-&amp;gt;records=0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;hash-&amp;gt;key_offset=key_offset;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;hash-&amp;gt;key_length=key_length;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;hash-&amp;gt;blength=1;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;hash-&amp;gt;get_key=get_key;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;hash-&amp;gt;&lt;/code&gt;&lt;code&gt;free&lt;/code&gt;&lt;code&gt;=free_element;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;hash-&amp;gt;flags=flags;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;hash-&amp;gt;charset=charset;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;DBUG_RETURN(my_init_dynamic_array_ci(&amp;amp;hash-&amp;gt;array, &lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                                       &lt;/code&gt;&lt;code&gt;sizeof&lt;/code&gt;&lt;code&gt;(HASH_LINK), size, growth_size));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_887311&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;&amp;lt;font size=&lt;/code&gt;&lt;code&gt;&quot;3&quot;&lt;/code&gt;&lt;code&gt;&amp;gt;   可以看到，_my_hash_init函数主要是初始化HASH结构体和hash-&amp;gt;array（DYNAMIC_ARRAY结构体）。&amp;lt;/font&amp;gt;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h1&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;strong&gt;动态HASH函数&lt;/strong&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_728621&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;&amp;lt;font size=&lt;/code&gt;&lt;code&gt;&quot;3&quot;&lt;/code&gt;&lt;code&gt;&amp;gt;   我们首先来看下hash函数的定义：&amp;lt;/font&amp;gt;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_7662&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;static&lt;/code&gt; &lt;code&gt;inline&lt;/code&gt; &lt;code&gt;char&lt;/code&gt;&lt;code&gt;*&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;my_hash_key(&lt;/code&gt;&lt;code&gt;const&lt;/code&gt; &lt;code&gt;HASH *hash, &lt;/code&gt;&lt;code&gt;const&lt;/code&gt; &lt;code&gt;uchar *record, &lt;/code&gt;&lt;code&gt;size_t&lt;/code&gt; &lt;code&gt;*length,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;my_bool first)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(hash-&amp;gt;get_key)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;(&lt;/code&gt;&lt;code&gt;char&lt;/code&gt;&lt;code&gt;*) (*hash-&amp;gt;get_key)(record,length,first);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;*length=hash-&amp;gt;key_length;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;(&lt;/code&gt;&lt;code&gt;char&lt;/code&gt;&lt;code&gt;*) record+hash-&amp;gt;key_offset;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;static&lt;/code&gt; &lt;code&gt;uint my_hash_mask(my_hash_value_type hashnr, &lt;/code&gt;&lt;code&gt;size_t&lt;/code&gt; &lt;code&gt;buffmax,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                         &lt;/code&gt;&lt;code&gt;size_t&lt;/code&gt; &lt;code&gt;maxlength)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;((hashnr &amp;amp; (buffmax-1)) &amp;lt; maxlength) &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;(hashnr &amp;amp; (buffmax-1));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;(hashnr &amp;amp; ((buffmax &amp;gt;&amp;gt; 1) -1));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div align=&quot;center&quot;&gt;
&lt;table width=&quot;400&quot; border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;2&quot; align=&quot;center&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;my_hash_key参数&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;说明&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;hash&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;HASH链表结构&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;record&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;带插入的元素的值&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;length&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;带插入元素的值长度&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;first&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;辅助参数&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_844892&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;&amp;lt;font size=&lt;/code&gt;&lt;code&gt;&quot;3&quot;&lt;/code&gt;&lt;code&gt;&amp;gt;   &amp;lt;/font&amp;gt;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div align=&quot;center&quot;&gt;
&lt;table width=&quot;400&quot; border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;2&quot; align=&quot;center&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;my_hash_mask参数&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;说明&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;hashnr&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;my_hash_key的计算结果&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;buffmax&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;hash结构体中的blength&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;maxlength&lt;/td&gt;
&lt;td align=&quot;center&quot; width=&quot;199&quot;&gt;实际桶的个数&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span style=&quot;font-size: small;&quot;&gt;    你可能要问我怎么有两个？其实这和我们平时使用的差不多，第一个函数my_hash_key是根据我们的值进行Hash &lt;/span&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Key计算，一般我们在&lt;/span&gt;&lt;span style=&quot;font-size: small;&quot;&gt;计算后，会对hash key进行一次模运算，以便计算结果在我们的bucket中。即my_hash_key的结果作为my_hash_mask的第一个输入参数。&lt;/span&gt;&lt;span style=&quot;font-size: small;&quot;&gt;其实到这里都是非常好理解的，唯一让我蛋疼的是my_hash_mask的实现，&lt;span style=&quot;color: #0000ff;&quot;&gt;其计算结果是和第二和第三个参数有关，即Hash结构体中的blength&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;和records有关&lt;/span&gt;。动态变化的，我去..&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: Verdana; font-size: small;&quot;&gt;     看到这里我迷惑了，我上网经过各种百度，谷歌，终于让我找到了一封Mysql Expert的回信：&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_180496&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;Hi!&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&quot;Yan&quot;&lt;/code&gt; &lt;code&gt;== Yan Yu &amp;lt;yan2...@facebook.com&amp;gt; writes:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;Yan&amp;gt; Dear MySQL experts:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;Yan&amp;gt;      Thank you so much &lt;/code&gt;&lt;code&gt;for&lt;/code&gt; &lt;code&gt;your reply to my previous Qs, they are very  &lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;Yan&amp;gt; helpful!&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;Yan&amp;gt;      Could someone please help me understand function my_hash_insert()  &lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;Yan&amp;gt; in mysys/hash.cc?&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;Yan&amp;gt; what are lines 352 -429 trying to achieve?  Are they just some  &lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;Yan&amp;gt; optimization to shuffle existing&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;Yan&amp;gt; hash entries in the table (since the existing hash entries may be in  &lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;Yan&amp;gt; the wrong slot due to chaining&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;Yan&amp;gt; in the &lt;/code&gt;&lt;code&gt;case&lt;/code&gt; &lt;code&gt;of hash collision)?&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;lt;strong&amp;gt;&amp;lt;font color=&lt;/code&gt;&lt;code&gt;&quot;#ff0000&quot;&lt;/code&gt;&lt;code&gt;&amp;gt;The hash algorithm is based on dynamic hashing without empty slots.&amp;lt;/font&amp;gt;&amp;lt;/strong&amp;gt;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;This means that when you insert a &lt;/code&gt;&lt;code&gt;new&lt;/code&gt; &lt;code&gt;key, in some cases a small set&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;of old keys needs to be moved to other buckets.  This is what the code&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;does.&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;Regards,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;Monty&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span style=&quot;font-size: small;&quot;&gt;      红色注释的地方是重点，dynamic hash，原来如此，动态hash，第一次听说，在网上下了个《Dynamic Hash Tables》的论文，&lt;/span&gt;&lt;span style=&quot;font-size: small;&quot;&gt;下面图解下基本原理。&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_847480&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;&amp;lt;a href=&lt;/code&gt;&lt;code&gt;&quot;&lt;a href=&quot;http://images.cnblogs.com/cnblogs_com/nocode/201110/201110142107072298.png&quot;&gt;http://images.cnblogs.com/cnblogs_com/nocode/201110/201110142107072298.png&lt;/a&gt;&quot;&lt;/code&gt;&lt;code&gt;&amp;gt;&amp;lt;img title=&lt;/code&gt;&lt;code&gt;&quot;image&quot;&lt;/code&gt; &lt;code&gt;style=&lt;/code&gt;&lt;code&gt;&quot;border-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;&quot;&lt;/code&gt; &lt;code&gt;alt=&lt;/code&gt;&lt;code&gt;&quot;image&quot;&lt;/code&gt; &lt;code&gt;src=&lt;/code&gt;&lt;code&gt;&quot;&lt;a href=&quot;http://images.cnblogs.com/cnblogs_com/nocode/201110/201110142107114127.png&quot;&gt;http://images.cnblogs.com/cnblogs_com/nocode/201110/201110142107114127.png&lt;/a&gt;&quot;&lt;/code&gt; &lt;code&gt;border=&lt;/code&gt;&lt;code&gt;&quot;0&quot;&lt;/code&gt; &lt;code&gt;height=&lt;/code&gt;&lt;code&gt;&quot;910&quot;&lt;/code&gt; &lt;code&gt;width=&lt;/code&gt;&lt;code&gt;&quot;570&quot;&lt;/code&gt;&lt;code&gt;&amp;gt;&amp;lt;&lt;/code&gt;&lt;code&gt;/a&lt;/code&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_729360&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;&amp;lt;font size=&lt;/code&gt;&lt;code&gt;&quot;3&quot;&lt;/code&gt;&lt;code&gt;&amp;gt;&amp;lt;&lt;/code&gt;&lt;code&gt;/font&lt;/code&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span style=&quot;font-size: small;&quot;&gt;动态Hash的本质是Hash函数的设计，图中给出的动态hash函数只是论文中提到的一个例子。下面就具体解读下Mysql中的hash插入——my_hash_insert&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h1&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;strong&gt;my_hash_insert非深入解析&lt;/strong&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;strong&gt;  &lt;/strong&gt;  首先给出my_hash_insert的源代码,代码在&lt;strong&gt;&lt;em&gt;mysys/hash.c&lt;/em&gt;&lt;/strong&gt;中。&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_709223&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;my_bool my_hash_insert(HASH *info, &lt;/code&gt;&lt;code&gt;const&lt;/code&gt; &lt;code&gt;uchar *record)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;int&lt;/code&gt; &lt;code&gt;flag;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;size_t&lt;/code&gt; &lt;code&gt;idx,halfbuff,first_&lt;a href=&quot;http://ourmysql.com/archives/tag/index&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 index 下的日志&quot;&gt;index&lt;/a&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;my_hash_value_type hash_nr;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;uchar *UNINIT_VAR(ptr_to_rec),*UNINIT_VAR(ptr_to_rec2);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;HASH_LINK *data,*empty,*UNINIT_VAR(gpos),*UNINIT_VAR(gpos2),*pos;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(HASH_UNIQUE &amp;amp; info-&amp;gt;flags)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;uchar *key= (uchar*) my_hash_key(info, record, &amp;amp;idx, 1);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(my_hash_search(info, key, idx))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;return&lt;/code&gt;&lt;code&gt;(TRUE);               &lt;/code&gt;&lt;code&gt;/* Duplicate entry */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;flag=0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(!(empty=(HASH_LINK*) alloc_dynamic(&amp;amp;info-&amp;gt;array)))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;return&lt;/code&gt;&lt;code&gt;(TRUE);               &lt;/code&gt;&lt;code&gt;/* No more memory */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;data=dynamic_element(&amp;amp;info-&amp;gt;array,0,HASH_LINK*);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;halfbuff= info-&amp;gt;blength &amp;gt;&amp;gt; 1;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;idx=first_index=info-&amp;gt;records-halfbuff;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(idx != info-&amp;gt;records)                &lt;/code&gt;&lt;code&gt;/* If some records */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;do&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;pos=data+idx;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;hash_nr=rec_hashnr(info,pos-&amp;gt;data);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(flag == 0)              &lt;/code&gt;&lt;code&gt;/* First loop; Check if ok */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(my_hash_mask(hash_nr, info-&amp;gt;blength, info-&amp;gt;records) != first_index)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;break&lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(!(hash_nr &amp;amp; halfbuff))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;{                       &lt;/code&gt;&lt;code&gt;/* Key will not move */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(!(flag &amp;amp; LOWFIND))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(flag &amp;amp; HIGHFIND)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;flag=LOWFIND | HIGHFIND;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;/* key shall be moved to the current empty position */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;gpos=empty;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;ptr_to_rec=pos-&amp;gt;data;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;empty=pos;              &lt;/code&gt;&lt;code&gt;/* This place is now free */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;else&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;flag=LOWFIND | LOWUSED;     &lt;/code&gt;&lt;code&gt;/* key isn't changed */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;gpos=pos;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;ptr_to_rec=pos-&amp;gt;data;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;else&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(!(flag &amp;amp; LOWUSED))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;/* Change link of previous LOW-key */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;gpos-&amp;gt;data=ptr_to_rec;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;gpos-&amp;gt;next= (uint) (pos-data);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;flag= (flag &amp;amp; HIGHFIND) | (LOWFIND | LOWUSED);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;gpos=pos;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;ptr_to_rec=pos-&amp;gt;data;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;else&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;{                       &lt;/code&gt;&lt;code&gt;/* key will be moved */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(!(flag &amp;amp; HIGHFIND))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;flag= (flag &amp;amp; LOWFIND) | HIGHFIND;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;/* key shall be moved to the last (empty) position */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;gpos2 = empty; empty=pos;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;ptr_to_rec2=pos-&amp;gt;data;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;else&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(!(flag &amp;amp; HIGHUSED))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;/* Change link of previous hash-key and save */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;gpos2-&amp;gt;data=ptr_to_rec2;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;gpos2-&amp;gt;next=(uint) (pos-data);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;flag= (flag &amp;amp; LOWFIND) | (HIGHFIND | HIGHUSED);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;gpos2=pos;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                    &lt;/code&gt;&lt;code&gt;ptr_to_rec2=pos-&amp;gt;data;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;while&lt;/code&gt; &lt;code&gt;((idx=pos-&amp;gt;next) != NO_RECORD);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;((flag &amp;amp; (LOWFIND | LOWUSED)) == LOWFIND)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;gpos-&amp;gt;data=ptr_to_rec;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;gpos-&amp;gt;next=NO_RECORD;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;((flag &amp;amp; (HIGHFIND | HIGHUSED)) == HIGHFIND)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;gpos2-&amp;gt;data=ptr_to_rec2;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;gpos2-&amp;gt;next=NO_RECORD;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;/* Check if we are at the empty position */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;idx= my_hash_mask(rec_hashnr(info, record), info-&amp;gt;blength, info-&amp;gt;records + 1);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;pos=data+idx;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(pos == empty)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;pos-&amp;gt;data=(uchar*) record;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;pos-&amp;gt;next=NO_RECORD;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;else&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;/* Check if more records in same hash-nr family */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;empty[0]=pos[0];&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;gpos= data + my_hash_rec_mask(info, pos, info-&amp;gt;blength, info-&amp;gt;records + 1);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(pos == gpos)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;pos-&amp;gt;data=(uchar*) record;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;pos-&amp;gt;next=(uint) (empty - data);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;else&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;pos-&amp;gt;data=(uchar*) record;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;pos-&amp;gt;next=NO_RECORD;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;movelink(data,(uint) (pos-data),(uint) (gpos-data),(uint) (empty-data));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(++info-&amp;gt;records == info-&amp;gt;blength)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;info-&amp;gt;blength+= info-&amp;gt;blength;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;return&lt;/code&gt;&lt;code&gt;(0);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span style=&quot;font-size: small;&quot;&gt;    同时给出动态hash函数如下：&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_70525&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;static&lt;/code&gt; &lt;code&gt;uint my_hash_mask(my_hash_value_type hashnr, &lt;/code&gt;&lt;code&gt;size_t&lt;/code&gt; &lt;code&gt;buffmax,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                         &lt;/code&gt;&lt;code&gt;size_t&lt;/code&gt; &lt;code&gt;maxlength)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;((hashnr &amp;amp; (buffmax-1)) &amp;lt; maxlength) &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;(hashnr &amp;amp; (buffmax-1));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;(hashnr &amp;amp; ((buffmax &amp;gt;&amp;gt; 1) -1));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_5088&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;&amp;lt;font size=&lt;/code&gt;&lt;code&gt;&quot;3&quot;&lt;/code&gt;&lt;code&gt;&amp;gt;  &amp;lt;/font&amp;gt;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span style=&quot;font-size: small;&quot;&gt;   可以看出，hash函数是hash key与buffmax的模运算，buffmax即HASH结构中的blength，由my_hash_insert中最后几行&lt;/span&gt;&lt;span style=&quot;font-size: small;&quot;&gt;代码可知：info-&amp;gt;blength+= info-&amp;gt;blength; 其初始值为1，&lt;strong&gt;即blength = 2^n&lt;/strong&gt;，而且blengh始终是大于records。这个动态hash函数的基本意思是&lt;strong&gt;key%（2^n）。&lt;/strong&gt;依然用图解这个动态hash函数。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://images.cnblogs.com/cnblogs_com/nocode/201110/201110142107218893.png&quot;&gt;&lt;img title=&quot;image&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/nocode/201110/201110142107237300.png&quot; alt=&quot;image&quot; width=&quot;490&quot; height=&quot;597&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: small;&quot;&gt;hash函数基本清楚了，但是mysql的具体实现还是比较值得探讨的。那封回信中也提到了without empty slots，是的，它这种实现方式是根据实际的数据量进行桶数的分配。我这里大概说下代码的流程（有兴趣的还需要大家自己仔细琢磨）。&lt;/span&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span style=&quot;font-size: small;&quot;&gt;根据flag去判断是否是否唯一Hash，如果是唯一Hash，去查找Hash表中是否存在重复值(dupliacate entry)，存在则报错。&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-size: small;&quot;&gt;进行桶分裂，对应代码中的if (idx != info-&amp;gt;records)分支。这个分支有些费解，稍微提示下：gpos和ptr_to_rec指示了低位需要移动的数据，gpos2和 ptr_to_rec2只是了高位需要移动的数据。LOWFIND表示低位存在值，LOWUSED表示低位是否进行了调整。HIGH的宏意义基本相同。 if (!(hash_nr &amp;amp; halfbuff)) 用于判断hash值存在高位还是低位。&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-size: small;&quot;&gt;计算新值对应的bucket号，插入。如果此位置上存在元素(一般情况都存在，除非是empty，概率比较小)，调整原始元素的位置。&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;h3  class=&quot;related_post_title&quot;&gt;相关文章&lt;/h3&gt;&lt;ul class=&quot;related_post&quot;&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1112&quot; title=&quot;mysql hash 破解提权&quot;&gt;mysql hash 破解提权&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1105&quot; title=&quot;Mysql源码学习——用户认证原理与实现&quot;&gt;Mysql源码学习——用户认证原理与实现&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1102&quot; title=&quot;Mysql源码学习——Thread Manager&quot;&gt;Mysql源码学习——Thread Manager&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1100&quot; title=&quot;Mysql源码学习——Connection Manager&quot;&gt;Mysql源码学习——Connection Manager&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1098&quot; title=&quot;Mysql源码学习——八度空间&quot;&gt;Mysql源码学习——八度空间&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1095&quot; title=&quot;Mysql源码学习——源码目录结构&quot;&gt;Mysql源码学习——源码目录结构&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1092&quot; title=&quot;Mysql源码学习——打造专属语法&quot;&gt;Mysql源码学习——打造专属语法&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1090&quot; title=&quot;Mysql源码学习——词法分析MYSQLlex&quot;&gt;Mysql源码学习——词法分析MYSQLlex&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1088&quot; title=&quot;Mysql源码学习笔记——偷窥线程&quot;&gt;Mysql源码学习笔记——偷窥线程&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1086&quot; title=&quot;Mysql的源码安装&quot;&gt;Mysql的源码安装&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
	标签：&lt;a href=&quot;http://ourmysql.com/archives/tag/hash&quot; title=&quot;Hash&quot; rel=&quot;tag&quot;&gt;Hash&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/category/advanced&quot; title=&quot;MySQL高级应用&quot; rel=&quot;tag&quot;&gt;MySQL高级应用&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/%e6%ba%90%e7%a0%81&quot; title=&quot;源码&quot; rel=&quot;tag&quot;&gt;源码&lt;/a&gt;&lt;br /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/620768936/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1107&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://ourmysql.com/archives/1107/feed</wfw:commentRss><slash:comments>0</slash:comments><description>Hash 链表的应用比较常见，其目的就是为了将不同的值映射到不同的位置，查找的时候直接找到相应的位置，而不需要传统的顺序遍历或是二分查找，从而达到减少查询 时间的目的。常规的hash是预定义一定的桶(bucket)，规定一个hash函数，然后进行散列。然而Mysql中的hash没有固定的 bucket，hash函数也是动态变化的，本文就进行非深入介绍。&lt;img src=&quot;http://www1.feedsky.com/t1/620768936/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1107&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>源码</category><category>MySQL高级应用</category><category>Hash</category><pubDate>Mon, 26 Mar 2012 13:49:55 +0800</pubDate><author>OurMySQL</author><comments>http://ourmysql.com/archives/1107#comments</comments><guid isPermaLink="false">http://ourmysql.com/?p=1107</guid><dc:creator>OurMySQL</dc:creator><fs:srclink>http://ourmysql.com/archives/1107</fs:srclink><fs:srcfeed>http://www.ourmysql.com/feed</fs:srcfeed><fs:itemid>feedsky/ourmysql/~7195843/620768936/5270018</fs:itemid></item><item><title>Mysql源码学习——用户认证原理与实现</title><link>http://ourmysql.com/archives/1105</link><content:encoded>&lt;p&gt;前几节跟踪了&lt;a href=&quot;http://ourmysql.com/archives/1100&quot; target=&quot;_blank&quot;&gt;Connection Manager&lt;/a&gt;和&lt;a href=&quot;http://ourmysql.com/archives/1102&quot; target=&quot;_blank&quot;&gt;Thread Manager&lt;/a&gt;，在连接的过程中，还有一个身份认证的过程，就是大家所熟悉的&lt;/p&gt;
&lt;p&gt;验证用户名和密码的过程，我们平时做一个系统的时候，很多时候都会涉及到身份验证。今天我们就来看下Mysql是如何进&lt;/p&gt;
&lt;p&gt;行验证的。（注意是登录，不是登陆^_^）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一、用户认证原理&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们在应用程序中实现验证的方式基本上都是创建一张用户表，里面至少包含username和password两个字段，&lt;/p&gt;
&lt;p&gt;password基本上都是加密后进行存储的。作为数据库，对用户的限制较多，不是像我说的仅仅只有username和password&lt;/p&gt;
&lt;p&gt;这么简单了。首先粗略的讲下访问控制。&lt;/p&gt;
&lt;p&gt;信息系统中，访问控制分为&lt;strong&gt;自主访问控制(DAC)&lt;/strong&gt;和&lt;strong&gt;强制访问控制(MAC)&lt;/strong&gt;。具体到DBMS，自主访问控制就是我们所熟悉&lt;/p&gt;
&lt;p&gt;的GRANT，REVOKE，大多数数据库都支持自助的访问控制。强制访问控制就是ORACLE中的LABEL，只有很少的一些系统支持MAC。&lt;/p&gt;
&lt;p&gt;严格来说，登录并不属于访问控制机制，而应该属于用户身份识别和认证。在Mysql中，将登录和DAC的相关接口都实现在了&lt;/p&gt;
&lt;p&gt;sql_acl.cc中(其实说登录是用户拥有的一种权限也未尝不可，正如ORACLE中的CREATE SESSION，不过登录并不仅仅是一种权&lt;/p&gt;
&lt;p&gt;限，还包含很多其他的属性)，从文件名大家可以看出来，ACL即ACCESS CONTROL LIST，访问控制列表，这是实现访问控制的&lt;/p&gt;
&lt;p&gt;基本方法。&lt;strong&gt;下图是Mysql的整个访问控制的流程&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://images.cnblogs.com/cnblogs_com/nocode/201108/201108302046147054.png&quot;&gt;&lt;img title=&quot;image001&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/nocode/201108/201108302048231497.png&quot; alt=&quot;image001&quot; width=&quot;443&quot; height=&quot;713&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Mysql中用户管理模块的信息存储在系统表&lt;strong&gt;mysql.User&lt;/strong&gt;中，这个表不仅仅存放了授权用户的基本信息，还存放一些权限&lt;/p&gt;
&lt;p&gt;信息。我们首先大概看一下这个表的结构。&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;+-----------------------+-----------------------------------+------+-----+---------+-------+

| Field | Type | Null | Key | Default | Extra |

+-----------------------+-----------------------------------+------+-----+---------+-------+

| Host | char(60) | NO | PRI | | |

| User | char(16) | NO | PRI | | |

| Password | char(41) | NO | | | |

| Select_priv | enum('N','Y') | NO | | N | |

| Insert_priv | enum('N','Y') | NO | | N | |

| Update_priv | enum('N','Y') | NO | | N | |

| Delete_priv | enum('N','Y') | NO | | N | |

| Create_priv | enum('N','Y') | NO | | N | |

| Drop_priv | enum('N','Y') | NO | | N | |

| Reload_priv | enum('N','Y') | NO | | N | |

| Shutdown_priv | enum('N','Y') | NO | | N | |

| Process_priv | enum('N','Y') | NO | | N | |

| File_priv | enum('N','Y') | NO | | N | |

| Grant_priv | enum('N','Y') | NO | | N | |

| References_priv | enum('N','Y') | NO | | N | |

| &lt;a href=&quot;http://ourmysql.com/archives/tag/index&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 index 下的日志&quot;&gt;Index&lt;/a&gt;_priv | enum('N','Y') | NO | | N | |

| Alter_priv | enum('N','Y') | NO | | N | |

| Show_db_priv | enum('N','Y') | NO | | N | |

| Super_priv | enum('N','Y') | NO | | N | |

| Create_tmp_table_priv | enum('N','Y') | NO | | N | |

| Lock_tables_priv | enum('N','Y') | NO | | N | |

| Execute_priv | enum('N','Y') | NO | | N | |

| Repl_slave_priv | enum('N','Y') | NO | | N | |

| Repl_client_priv | enum('N','Y') | NO | | N | |

| Create_view_priv | enum('N','Y') | NO | | N | |

| Show_view_priv | enum('N','Y') | NO | | N | |

| Create_routine_priv | enum('N','Y') | NO | | N | |

| Alter_routine_priv | enum('N','Y') | NO | | N | |

| Create_user_priv | enum('N','Y') | NO | | N | |

| Event_priv | enum('N','Y') | NO | | N | |

| Trigger_priv | enum('N','Y') | NO | | N | |

| ssl_type | enum('','ANY','X509','SPECIFIED') | NO | | | |

| ssl_cipher | blob | NO | | NULL | |

| x509_issuer | blob | NO | | NULL | |

| x509_subject | blob | NO | | NULL | |

| max_questions | int(11) unsigned | NO | | 0 | |

| max_updates | int(11) unsigned | NO | | 0 | |

| max_connections | int(11) unsigned | NO | | 0 | |

| max_user_connections | int(11) unsigned | NO | | 0 | |

+-----------------------+-----------------------------------+------+-----+---------+-------+

39 rows in set (0.01 sec)&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这个表包含了39个字段，对于我们登录来说，应该主要是使用前三个字段，即Host，User，Password。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;mysql&amp;gt; select Host,User,Password from user;

+-----------+------+----------+

| Host | User | Password |

+-----------+------+----------+

| localhost | root | |

| 127.0.0.1 | root | |

| localhost | | |

+-----------+------+----------+

3 rows in set (0.00 sec)&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这里比我们预想的只需要用户名和密码的方式有所出入，&lt;strong&gt;多了一个Host字段&lt;/strong&gt;，这个字段起到什么作用呢？！原来Mysql的登录认证不仅需要验证用户名和密码，还需要验证连接的主机地址，这样也是为了提高安全性吧。那如果我想一个用户在任何地址都可以进行登录岂不是要设置很多地址？Mysql提供了通配符，可以设置Host字段为*，这就代表可以匹配任何Host。具体看下这三行的意思，这三行的密码均为空。针对root用户，不需要输入密码，客户端的地址为本机。第三行的用户名为空，Host为localhost，说明本地的任何用户均可以进行登录，即使是个不存在的用户也可以登录成功，但是仅限于登录，没有其他相关的权限，无法进行实际操作。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;二、源码跟踪&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在Connection Manager中提到了login_connection函数用于检查用户名和密码等相关信息，其源码如下（&lt;strong&gt;重点的函数代码&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;会着色&lt;/strong&gt;）：&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;static bool login_connection(THD *thd)
{
  NET *net= &amp;amp;thd-&amp;gt;net;
  int error;
  DBUG_ENTER(&quot;login_connection&quot;);
  DBUG_PRINT(&quot;info&quot;, (&quot;login_connection called by thread %lu&quot;,
                      thd-&amp;gt;thread_id));

  /* Use &quot;connect_timeout&quot; value during connection phase */
  my_net_set_read_timeout(net, connect_timeout);
  my_net_set_write_timeout(net, connect_timeout);
error= check_connection(thd); //此处是验证的具体函数

  net_end_statement(thd);

  if (error)
  {                        // Wrong permissions
#ifdef __NT__
    if (vio_type(net-&amp;gt;vio) == VIO_TYPE_NAMEDPIPE)
      my_sleep(1000);                /* must wait after eof() */
#endif
    statistic_increment(aborted_connects,&amp;amp;LOCK_status);
    DBUG_RETURN(1);
  }
  /* Connect completed, set read/write timeouts back to default */
  my_net_set_read_timeout(net, thd-&amp;gt;variables.net_read_timeout);
  my_net_set_write_timeout(net, thd-&amp;gt;variables.net_write_timeout);
  DBUG_RETURN(0);
}&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;此函数主要是功能是调用函数check_connection进行用户认证,由于函数check_connection过长，对其进行简化，如下所示：&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt; static int check_connection(THD *thd)

{
  uint connect_errors= 0;
  NET *net= &amp;amp;thd-&amp;gt;net;
  ulong pkt_len= 0;
  char *end;

  DBUG_PRINT(&quot;info&quot;,
             (&quot;New connection received on %s&quot;, vio_description(net-&amp;gt;vio)));
#ifdef SIGNAL_WITH_VIO_CLOSE
  thd-&amp;gt;set_active_vio(net-&amp;gt;vio);
#endif

  if (!thd-&amp;gt;main_security_ctx.host)         // If TCP/IP connection
  {
    char ip[30];

    if (vio_peer_addr(net-&amp;gt;vio, ip, &amp;amp;thd-&amp;gt;peer_port))
    {
      my_error(ER_BAD_HOST_ERROR, MYF(0), thd-&amp;gt;main_security_ctx.host_or_ip);
      return 1;
    }
    if (!(thd-&amp;gt;main_security_ctx.ip= my_strdup(ip,MYF(MY_WME))))
      return 1; /* The error is set by my_strdup(). */
    thd-&amp;gt;main_security_ctx.host_or_ip= thd-&amp;gt;main_security_ctx.ip;
    vio_in_addr(net-&amp;gt;vio,&amp;amp;thd-&amp;gt;remote.sin_addr);
    if (!(specialflag &amp;amp; SPECIAL_NO_RESOLVE))
    {
      vio_in_addr(net-&amp;gt;vio,&amp;amp;thd-&amp;gt;remote.sin_addr);
      thd-&amp;gt;main_security_ctx.host=
        ip_to_hostname(&amp;amp;thd-&amp;gt;remote.sin_addr, &amp;amp;connect_errors);
      /* Cut very long hostnames to avoid possible overflows */
      if (thd-&amp;gt;main_security_ctx.host)
      {
        if (thd-&amp;gt;main_security_ctx.host != my_localhost)
          thd-&amp;gt;main_security_ctx.host[min(strlen(thd-&amp;gt;main_security_ctx.host),
                                          HOSTNAME_LENGTH)]= 0;
        thd-&amp;gt;main_security_ctx.host_or_ip= thd-&amp;gt;main_security_ctx.host;
      }
      if (connect_errors &amp;gt; max_connect_errors)
      {
        my_error(ER_HOST_IS_BLOCKED, MYF(0), thd-&amp;gt;main_security_ctx.host_or_ip);
        return 1;
      }
    }
    ...

if (acl_check_host(thd-&amp;gt;main_security_ctx.host, thd-&amp;gt;main_security_ctx.ip))//此处验证主机名或IP是否存在

    {
      my_error(ER_HOST_NOT_PRIVILEGED, MYF(0),
               thd-&amp;gt;main_security_ctx.host_or_ip);
      return 1;
    }
  }
  else /* Hostname given means that the connection was on a socket */
  {
   ...
  }
  vio_keepalive(net-&amp;gt;vio, TRUE);

  ...

  char *user= end;
  char *passwd= strend(user)+1;
  uint user_len= passwd - user - 1;
  char *db= passwd;
  char db_buff[NAME_LEN + 1];           // buffer to store db in utf8
  char user_buff[USERNAME_LENGTH + 1];    // buffer to store user in utf8
  uint dummy_errors;

  uint passwd_len= thd-&amp;gt;client_capabilities &amp;amp; CLIENT_SECURE_CONNECTION ?
    (uchar)(*passwd++) : strlen(passwd);
  db= thd-&amp;gt;client_capabilities &amp;amp; CLIENT_CONNECT_WITH_DB ?
    db + passwd_len + 1 : 0;
  uint db_len= db ? strlen(db) : 0;

  if (passwd + passwd_len + db_len &amp;gt; (char *)net-&amp;gt;read_pos + pkt_len)
  {
    inc_host_errors(&amp;amp;thd-&amp;gt;remote.sin_addr);
    my_error(ER_HANDSHAKE_ERROR, MYF(0), thd-&amp;gt;main_security_ctx.host_or_ip);
    return 1;
  }

...
  /* If username starts and ends in &quot;'&quot;, chop them off */
  if (user_len &amp;gt; 1 &amp;amp;&amp;amp; user[0] == '\'' &amp;amp;&amp;amp; user[user_len - 1] == '\'')
  {
    user[user_len-1]= 0;
    user++;
    user_len-= 2;
  }

  if (thd-&amp;gt;main_security_ctx.user)
    x_free(thd-&amp;gt;main_security_ctx.user);
  if (!(thd-&amp;gt;main_security_ctx.user= my_strdup(user, MYF(MY_WME))))
    return 1; /* The error is set by my_strdup(). */
  return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);//验证用户名和密码

}&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;上面的源码主要做了如下几件事情：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;获取客户端的IP和主机名&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;acl_check_host&lt;/strong&gt;函数验证USER表中是否存在相应的IP或HOST，如果不存在直接报错&lt;/li&gt;
&lt;li&gt;获取用户名和密码&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;check_user&lt;/strong&gt;函数验证用户名和密码(不输入用户名默认为ODBC)，如果系统表中不存在匹配的报错返回&lt;/li&gt;
&lt;li&gt;获取用户的权限列表，&lt;strong&gt;验证用户的相关属性是否合法&lt;/strong&gt;，如连接数是否超过上限，连接是否超时，操作是否超过限制等信息，如果不合法，则报错返回。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;由于在一个认证的过程中涉及到的东西比较多，各个方面吧，我不能一一跟踪，只能大概了解其中的实现流程，捡重点进行&lt;/p&gt;
&lt;p&gt;跟踪，有兴趣的童鞋自己具体跟踪吧&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;题外话：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Mysql中权限系统表都是在系统启动时，载入内存的（当然User表也是这样），一般情况下，不需要进行频繁的授权和回收操作，这中情况下，权限表基本保持不变，将其在系统启动的时候载入内存的好处自然是快速的进行权限判断，减少磁盘的I/O，你懂的^_^。有好处自然有坏处，就是在频繁进行授权和回收相关操作时，权限表需要重新载入内存，Mysql为了避免这种情况，在手册中已经说的很清楚了，授权和回收只会反应到磁盘中，内存的数据字典信息是不会改变的，如果想立即生效，需要调用FLUSH PRIVILEGES系统函数，这个系统函数的工作应该就是对权限系统表的RELOAD。&lt;/p&gt;
&lt;p&gt;下篇进入实质性的介绍，通过跟踪一个建表语句，来学习Mysql是如何存储表的元数据的，即&lt;strong&gt;frm格式文件的剖析&lt;/strong&gt;。&lt;/p&gt;
&lt;h3  class=&quot;related_post_title&quot;&gt;相关文章&lt;/h3&gt;&lt;ul class=&quot;related_post&quot;&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1107&quot; title=&quot;Mysql源码学习——没那么简单的Hash&quot;&gt;Mysql源码学习——没那么简单的Hash&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1102&quot; title=&quot;Mysql源码学习——Thread Manager&quot;&gt;Mysql源码学习——Thread Manager&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1100&quot; title=&quot;Mysql源码学习——Connection Manager&quot;&gt;Mysql源码学习——Connection Manager&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1098&quot; title=&quot;Mysql源码学习——八度空间&quot;&gt;Mysql源码学习——八度空间&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1095&quot; title=&quot;Mysql源码学习——源码目录结构&quot;&gt;Mysql源码学习——源码目录结构&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1092&quot; title=&quot;Mysql源码学习——打造专属语法&quot;&gt;Mysql源码学习——打造专属语法&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1090&quot; title=&quot;Mysql源码学习——词法分析MYSQLlex&quot;&gt;Mysql源码学习——词法分析MYSQLlex&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1088&quot; title=&quot;Mysql源码学习笔记——偷窥线程&quot;&gt;Mysql源码学习笔记——偷窥线程&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1086&quot; title=&quot;Mysql的源码安装&quot;&gt;Mysql的源码安装&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1084&quot; title=&quot;MySQL源码学习——DBUG调试&quot;&gt;MySQL源码学习——DBUG调试&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
	标签：&lt;a href=&quot;http://ourmysql.com/archives/category/advanced&quot; title=&quot;MySQL高级应用&quot; rel=&quot;tag&quot;&gt;MySQL高级应用&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/%e6%ba%90%e7%a0%81&quot; title=&quot;源码&quot; rel=&quot;tag&quot;&gt;源码&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/%e8%ae%a4%e8%af%81&quot; title=&quot;认证&quot; rel=&quot;tag&quot;&gt;认证&lt;/a&gt;&lt;br /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/620768937/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1105&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://ourmysql.com/archives/1105/feed</wfw:commentRss><slash:comments>0</slash:comments><description>Mysql中权限系统表都是在系统启动时，载入内存的（当然User表也是这样），一般情况下，不需要进行频繁的授权和回收操作，这中情况下，权限表基本保持不变，将其在系统启动的时候载入内存的好处自然是快速的进行权限判断，减少磁盘的I/O，你懂的^_^。有好处自然有坏处，就是在频繁进行授权和回收相关操作时，权限表需要重新载入内存，Mysql为了避免这种情况，在手册中已经说的很清楚了，授权和回收只会反应到磁盘中，内存的数据字典信息是不会改变的，如果想立即生效，需要调用FLUSH PRIVILEGES系统函数，这个系统函数的工作应该就是对权限系统表的RELOAD。&lt;img src=&quot;http://www1.feedsky.com/t1/620768937/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1105&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>认证</category><category>源码</category><category>MySQL高级应用</category><pubDate>Mon, 26 Mar 2012 13:48:33 +0800</pubDate><author>OurMySQL</author><comments>http://ourmysql.com/archives/1105#comments</comments><guid isPermaLink="false">http://ourmysql.com/?p=1105</guid><dc:creator>OurMySQL</dc:creator><fs:srclink>http://ourmysql.com/archives/1105</fs:srclink><fs:srcfeed>http://www.ourmysql.com/feed</fs:srcfeed><fs:itemid>feedsky/ourmysql/~7195843/620768937/5270018</fs:itemid></item><item><title>Mysql源码学习——Thread Manager</title><link>http://ourmysql.com/archives/1102</link><content:encoded>&lt;div id=&quot;cnblogs_post_body&quot;&gt;
&lt;p&gt;&lt;strong&gt;一、前言&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;上篇的&lt;a href=&quot;http://www.cnblogs.com/nocode/archive/2011/08/21/2147781.html&quot;&gt;Connection Manager&lt;/a&gt;中，曾提及对于一个新到来的Connection，服务器会创建一个新的线程来处理这个连接。&lt;/p&gt;
&lt;p&gt;其实没那么简单，为了提高系统效率，减少频繁创建线程和中止线程的系统消耗，Mysql使用了线程缓冲区的概念，即如果&lt;/p&gt;
&lt;p&gt;一个连接断开，则并不销毁承载其的线程，而是将此线程放入线程缓冲区，并处于挂起状态，当下一个新的Connection到来&lt;/p&gt;
&lt;p&gt;时，首先去线程缓冲区去查找是否有空闲的线程，如果有，则使用之，如果没有则新建线程。本问主要介绍这个线程缓冲区，&lt;/p&gt;
&lt;p&gt;首先介绍下基本的概念。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;二、基本概念&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.线程创建函数&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;大家知道，Mysql现在是插件式的存储引擎，只要实现规定的接口，就可实现自己的存储引擎。故Mysql的线程创建除了&lt;/p&gt;
&lt;p&gt;出现在主服务器框架外，存储引擎也可能会进行线程的创建。通过设置断点，在我调试的版本中，发现了两个创建线程的函数。&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_418463&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;pthread_create：Mysql自用的创建线程函数&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;os_thread_create：存储引擎innobase的创建线程的函数&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;os_thread_create是存储引擎innobase的线程函数，先搁浅不研究了，重点看下pthread_create，首先看下其源码。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_528910&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;int&lt;/code&gt; &lt;code&gt;pthread_create(pthread_t *thread_id, pthread_attr_t *attr,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;           &lt;/code&gt;&lt;code&gt;pthread_handler func, &lt;/code&gt;&lt;code&gt;void&lt;/code&gt; &lt;code&gt;*param)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;HANDLE&lt;/code&gt; &lt;code&gt;hThread;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;struct&lt;/code&gt; &lt;code&gt;pthread_map *map;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;&lt;a href=&quot;http://ourmysql.com/archives/tag/dbug&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 DBUG 下的日志&quot;&gt;DBUG&lt;/a&gt;_ENTER(&lt;/code&gt;&lt;code&gt;&quot;pthread_create&quot;&lt;/code&gt;&lt;code&gt;);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(!(map=&lt;/code&gt;&lt;code&gt;malloc&lt;/code&gt;&lt;code&gt;(&lt;/code&gt;&lt;code&gt;sizeof&lt;/code&gt;&lt;code&gt;(*map))))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;DBUG_RETURN(-1);&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;map-&amp;gt;func=func; map-&amp;gt;param=param;&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_274572&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;pthread_mutex_lock(&amp;amp;THR_LOCK_thread);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;#ifdef __BORLANDC__&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;hThread=(&lt;/code&gt;&lt;code&gt;HANDLE&lt;/code&gt;&lt;code&gt;)_beginthread((&lt;/code&gt;&lt;code&gt;void&lt;/code&gt;&lt;code&gt;(_USERENTRY *)(&lt;/code&gt;&lt;code&gt;void&lt;/code&gt; &lt;code&gt;*)) pthread_start,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                   &lt;/code&gt;&lt;code&gt;attr-&amp;gt;dwStackSize ? attr-&amp;gt;dwStackSize :&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                   &lt;/code&gt;&lt;code&gt;65535, (&lt;/code&gt;&lt;code&gt;void&lt;/code&gt;&lt;code&gt;*) map);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;#else&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;hThread=(HANDLE)_beginthread((void( __cdecl *)(void *)) pthread_start, attr-&amp;gt;dwStackSize ? attr-&amp;gt;dwStackSize : 65535, (void*) map);&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_227785&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;#endif&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;DBUG_PRINT(&lt;/code&gt;&lt;code&gt;&quot;info&quot;&lt;/code&gt;&lt;code&gt;, (&lt;/code&gt;&lt;code&gt;&quot;hThread=%lu&quot;&lt;/code&gt;&lt;code&gt;,(&lt;/code&gt;&lt;code&gt;long&lt;/code&gt;&lt;code&gt;) hThread));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;*thread_id=map-&amp;gt;pthreadself=hThread;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;pthread_mutex_unlock(&amp;amp;THR_LOCK_thread);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(hThread == (&lt;/code&gt;&lt;code&gt;HANDLE&lt;/code&gt;&lt;code&gt;) -1)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;int&lt;/code&gt; &lt;code&gt;error=&lt;/code&gt;&lt;code&gt;errno&lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;DBUG_PRINT(&lt;/code&gt;&lt;code&gt;&quot;error&quot;&lt;/code&gt;&lt;code&gt;,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;           &lt;/code&gt;&lt;code&gt;(&lt;/code&gt;&lt;code&gt;&quot;Can't create thread to handle request (error %d)&quot;&lt;/code&gt;&lt;code&gt;,error));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;DBUG_RETURN(error ? error : -1);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;VOID&lt;/code&gt;&lt;code&gt;(SetThreadPriority(hThread, attr-&amp;gt;priority)) ;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;DBUG_RETURN(0);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;上面代码首先构造了一个map结构体，成员分别是函数地址和传入参数。然后调用操作系统的接口，_beginthread,但是执行函数并不是传入的函数——func，而是pthread_start,参数为map。继续跟踪pthread_start。&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_114041&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;pthread_handler_t pthread_start(&lt;/code&gt;&lt;code&gt;void&lt;/code&gt; &lt;code&gt;*param)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;pthread_handler&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;func=((struct pthread_map *) param)-&amp;gt;func&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_805932&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;void&lt;/code&gt; &lt;code&gt;*func_param=((&lt;/code&gt;&lt;code&gt;struct&lt;/code&gt; &lt;code&gt;pthread_map *) param)-&amp;gt;param;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;my_thread_init();         &lt;/code&gt;&lt;code&gt;/* Will always succeed in windows */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;pthread_mutex_lock(&amp;amp;THR_LOCK_thread);   &lt;/code&gt;&lt;code&gt;/* Wait for beginthread to return */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;win_pthread_self=((&lt;/code&gt;&lt;code&gt;struct&lt;/code&gt; &lt;code&gt;pthread_map *) param)-&amp;gt;pthreadself;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;pthread_mutex_unlock(&amp;amp;THR_LOCK_thread);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;free&lt;/code&gt;&lt;code&gt;((&lt;/code&gt;&lt;code&gt;char&lt;/code&gt;&lt;code&gt;*) param);            &lt;/code&gt;&lt;code&gt;/* Free param from create */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;pthread_exit((&lt;/code&gt;&lt;code&gt;void&lt;/code&gt;&lt;code&gt;*) (*func)(func_param));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;0;               &lt;/code&gt;&lt;code&gt;/* Safety */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;可以看出，pthread_start中调用了map的func元素，作为真正执行的函数体。OK,创建线程的函数跟踪到此！&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.服务器启动时创建了哪些函数？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;通过在两个创建线程的地方设置断点，总结了下，在服务器启动时，创建了如下的线程。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pthread_create创建的线程&lt;/strong&gt;：&lt;/p&gt;
&lt;table width=&quot;428&quot; border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; width=&quot;217&quot;&gt;创建线程函数&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;209&quot;&gt;线程执行函数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; width=&quot;217&quot;&gt;create_shutdown_thread&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;209&quot;&gt;handle_shutdown&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; width=&quot;217&quot;&gt;start_handle_manager&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;209&quot;&gt;handle_manager&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; width=&quot;217&quot;&gt;handle_connections_methods&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;209&quot;&gt;handle_connections_sockets&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;innobase的os_thread_create创建的线程：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;table width=&quot;563&quot; border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; width=&quot;277&quot;&gt;创建线程函数&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;284&quot;&gt;线程执行函数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; width=&quot;277&quot;&gt;innobase_start_or_create_for_mysql&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;284&quot;&gt;io_handler_thread（4个）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; width=&quot;277&quot;&gt;recv_recovery_from_checkpoint_finish&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;284&quot;&gt;trx_rollback_or_clean_all_without_sess&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; width=&quot;277&quot;&gt;innobase_start_or_create_for_mysql&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;284&quot;&gt;srv_lock_timeout_thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; width=&quot;277&quot;&gt;&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;284&quot;&gt;srv_error_monitor_thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; width=&quot;277&quot;&gt;&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;284&quot;&gt;srv_monitor_thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; width=&quot;277&quot;&gt;&lt;/td&gt;
&lt;td valign=&quot;top&quot; width=&quot;284&quot;&gt;srv_master_thread&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;还可以在调试过程中，通过暂停来看此时服务器中的线程，如下图：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://images.cnblogs.com/cnblogs_com/nocode/201108/201108271517568307.jpg&quot;&gt;&lt;img title=&quot;1&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/nocode/201108/201108271517561829.jpg&quot; alt=&quot;1&quot; width=&quot;530&quot; height=&quot;281&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;三、线程缓冲池&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Mysql支持线程缓存，在多线程连接模式下，如果连接断开后，将这个线程放入空闲线程缓冲区，在下次有连接到来时，&lt;/p&gt;
&lt;p&gt;先去缓冲池中查找是否有空闲线程，有则用之，无则创建。启动时可以设置线程缓冲池的数目：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_41496&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;Mysqld.exe --thread_cache_size=10&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;在一个连接断开时，会调用cache_thread函数，将空闲的线程加入到cache中，以备后用。源码如下：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_542247&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;static&lt;/code&gt; &lt;code&gt;bool&lt;/code&gt; &lt;code&gt;cache_thread()&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;safe_mutex_assert_owner(&amp;amp;LOCK_thread_count);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;cached_thread_count &amp;lt; thread_cache_size&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_835008&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;     &lt;/code&gt;&lt;code&gt;! abort_loop &amp;amp;&amp;amp; !kill_cached_threads)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt; &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;   &lt;/code&gt;&lt;code&gt;/* Don't kill the thread, just put it in cache for reuse */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;   &lt;/code&gt;&lt;code&gt;DBUG_PRINT(&lt;/code&gt;&lt;code&gt;&quot;info&quot;&lt;/code&gt;&lt;code&gt;, (&lt;/code&gt;&lt;code&gt;&quot;Adding thread to cache&quot;&lt;/code&gt;&lt;code&gt;));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;   &lt;/code&gt;&lt;code&gt;cached_thread_count++;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;   &lt;/code&gt;&lt;code&gt;while&lt;/code&gt; &lt;code&gt;(!abort_loop &amp;amp;&amp;amp; ! wake_thread &amp;amp;&amp;amp; ! kill_cached_threads)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;     &lt;/code&gt;&lt;code&gt;(&lt;/code&gt;&lt;code&gt;void&lt;/code&gt;&lt;code&gt;) pthread_cond_wait(&amp;amp;COND_thread_cache, &amp;amp;LOCK_thread_count);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;   &lt;/code&gt;&lt;code&gt;cached_thread_count--;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;   &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(kill_cached_threads)&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;pthread_cond_signal(&amp;amp;COND_flush_thread_cache);&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_463063&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(wake_thread)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;THD *thd;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;wake_thread--;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;thd= thread_cache.get();&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;thd-&amp;gt;thread_stack= (&lt;/code&gt;&lt;code&gt;char&lt;/code&gt;&lt;code&gt;*) &amp;amp;thd;          &lt;/code&gt;&lt;code&gt;// For store_globals&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;(&lt;/code&gt;&lt;code&gt;void&lt;/code&gt;&lt;code&gt;) thd-&amp;gt;store_globals();&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;/*&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;THD::mysys_var::abort is associated with physical thread rather&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;than with THD object. So we need to reset this flag before using&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;this thread for handling of new THD object/connection.&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;*/&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;thd-&amp;gt;mysys_var-&amp;gt;&lt;/code&gt;&lt;code&gt;abort&lt;/code&gt;&lt;code&gt;= 0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;thd-&amp;gt;thr_create_utime= my_micro_time();&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;threads.append(thd);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;return&lt;/code&gt;&lt;code&gt;(1);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;return&lt;/code&gt;&lt;code&gt;(0);&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_308397&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;上面我们的启动参数设置线程缓冲区为10，此时对应代码里面的thread_cache_size = 10，cached_thread_count记录&lt;/p&gt;
&lt;p&gt;了此刻cache中的空闲线程数目，只有在cache未满的情况下，才会将新的空闲线程加入缓冲池中。加入到缓冲区其实就是将线&lt;/p&gt;
&lt;p&gt;程挂起，pthread_cond_wait函数便是线程等待函数，在此函数中，会调用WaitForMultipleObjects进行事件等待。具体源码&lt;/p&gt;
&lt;p&gt;如下：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_464553&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;int&lt;/code&gt; &lt;code&gt;pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                           &lt;/code&gt;&lt;code&gt;struct&lt;/code&gt; &lt;code&gt;timespec *abstime)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;int&lt;/code&gt; &lt;code&gt;result;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;long&lt;/code&gt; &lt;code&gt;timeout; &lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;union&lt;/code&gt; &lt;code&gt;ft64 now;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt;&lt;code&gt;( abstime != NULL )&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;GetSystemTimeAsFileTime(&amp;amp;now.ft);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;/*&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;Calculate time left to abstime&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;- subtract start time from current time(values are in 100ns units)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;- convert to millisec by dividing with 10000&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;*/&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;timeout= (&lt;/code&gt;&lt;code&gt;long&lt;/code&gt;&lt;code&gt;)((abstime-&amp;gt;tv.i64 - now.i64) / 10000);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;/* Don't allow the timeout to be negative */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(timeout &amp;lt; 0)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;timeout= 0L;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;/*&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;Make sure the calucated timeout does not exceed original timeout&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;value which could cause &quot;wait for ever&quot; if system time changes&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;*/&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(timeout &amp;gt; abstime-&amp;gt;max_timeout_msec)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;timeout= abstime-&amp;gt;max_timeout_msec;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;else&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;/* No time specified; don't expire */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;timeout= INFINITE;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;/* &lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;Block access if previous broadcast hasn't finished.&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;This is just for safety and should normally not&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;affect the total time spent in this function.&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;*/&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;WaitForSingleObject(cond-&amp;gt;broadcast_block_event, INFINITE);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;EnterCriticalSection(&amp;amp;cond-&amp;gt;lock_waiting);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;cond-&amp;gt;waiting++;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;LeaveCriticalSection(&amp;amp;cond-&amp;gt;lock_waiting);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;LeaveCriticalSection(mutex);&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;result= WaitForMultipleObjects(2, cond-&amp;gt;events, FALSE, timeout);&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_20624&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;EnterCriticalSection(&amp;amp;cond-&amp;gt;lock_waiting);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;cond-&amp;gt;waiting--;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(cond-&amp;gt;waiting == 0)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;/*&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;We're the last waiter to be notified or to stop waiting, so&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;reset the manual event. &lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;*/&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;/* Close broadcast gate */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;ResetEvent(cond-&amp;gt;events[BROADCAST]);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;/* Open block gate */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;SetEvent(cond-&amp;gt;broadcast_block_event);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;LeaveCriticalSection(&amp;amp;cond-&amp;gt;lock_waiting);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;EnterCriticalSection(mutex);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;result == WAIT_TIMEOUT ? ETIMEDOUT : 0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;此处是等待时间，何处进行事件通知呢？我们再次来到上篇所提及的为新的连接创建线程的代码中：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_131475&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;void&lt;/code&gt; &lt;code&gt;create_thread_to_handle_connection(THD *thd)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(cached_thread_count &amp;gt; wake_thread)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;/* Get thread from cache */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;thread_cache.append(thd);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;wake_thread++;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;pthread_cond_signal(&amp;amp;COND_thread_cache);&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_202994&quot;&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;Else&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;...&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;上篇文章我们其实只讲了ELSE分支，而忽略了IF分支。wake_thread代表了唤醒的线程数，即在线程缓冲区中被再次使用的&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://ourmysql.com/archives/tag/%e7%ba%bf%e7%a8%8b&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 线程 下的日志&quot;&gt;线程&lt;/a&gt;，如果cache中的总数&amp;gt;被重新使用的数目，说明还有空闲的线程，此时进入if分支，调用phtread_cond_signal唤醒上面挂起&lt;/p&gt;
&lt;p&gt;的空闲线程。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;线程管理就到此为止了，这里只是介绍了下线程缓冲区的工作原理，并没有具体去介绍如何利用EVENT进行线程的挂起和唤醒，这些都是借助了操作系统的特性，有兴趣的可以自己研究下。这篇就到此为止，下节会介绍Mysql的用户身份认证原理和实现。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PS. 男怕入错行，夜半三更忙，一行又一行&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h3  class=&quot;related_post_title&quot;&gt;相关文章&lt;/h3&gt;&lt;ul class=&quot;related_post&quot;&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1107&quot; title=&quot;Mysql源码学习——没那么简单的Hash&quot;&gt;Mysql源码学习——没那么简单的Hash&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1105&quot; title=&quot;Mysql源码学习——用户认证原理与实现&quot;&gt;Mysql源码学习——用户认证原理与实现&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1100&quot; title=&quot;Mysql源码学习——Connection Manager&quot;&gt;Mysql源码学习——Connection Manager&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1098&quot; title=&quot;Mysql源码学习——八度空间&quot;&gt;Mysql源码学习——八度空间&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1095&quot; title=&quot;Mysql源码学习——源码目录结构&quot;&gt;Mysql源码学习——源码目录结构&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1092&quot; title=&quot;Mysql源码学习——打造专属语法&quot;&gt;Mysql源码学习——打造专属语法&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1090&quot; title=&quot;Mysql源码学习——词法分析MYSQLlex&quot;&gt;Mysql源码学习——词法分析MYSQLlex&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1088&quot; title=&quot;Mysql源码学习笔记——偷窥线程&quot;&gt;Mysql源码学习笔记——偷窥线程&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1086&quot; title=&quot;Mysql的源码安装&quot;&gt;Mysql的源码安装&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1084&quot; title=&quot;MySQL源码学习——DBUG调试&quot;&gt;MySQL源码学习——DBUG调试&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
	标签：&lt;a href=&quot;http://ourmysql.com/archives/category/advanced&quot; title=&quot;MySQL高级应用&quot; rel=&quot;tag&quot;&gt;MySQL高级应用&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/thread-manager&quot; title=&quot;Thread Manager&quot; rel=&quot;tag&quot;&gt;Thread Manager&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/%e6%ba%90%e7%a0%81&quot; title=&quot;源码&quot; rel=&quot;tag&quot;&gt;源码&lt;/a&gt;&lt;br /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/620768938/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1102&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://ourmysql.com/archives/1102/feed</wfw:commentRss><slash:comments>0</slash:comments><description>为了提高系统效率，减少频繁创建线程和中止线程的系统消耗，Mysql使用了线程缓冲区的概念，即如果 一个连接断开，则并不销毁承载其的线程，而是将此线程放入线程缓冲区，并处于挂起状态，当下一个新的Connection到来 时，首先去线程缓冲区去查找是否有空闲的线程，如果有，则使用之，如果没有则新建线程。本问主要介绍这个线程缓冲区， 首先介绍下基本的概念&lt;img src=&quot;http://www1.feedsky.com/t1/620768938/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1102&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>源码</category><category>Thread Manager</category><category>MySQL高级应用</category><pubDate>Mon, 26 Mar 2012 13:42:04 +0800</pubDate><author>OurMySQL</author><comments>http://ourmysql.com/archives/1102#comments</comments><guid isPermaLink="false">http://ourmysql.com/?p=1102</guid><dc:creator>OurMySQL</dc:creator><fs:srclink>http://ourmysql.com/archives/1102</fs:srclink><fs:srcfeed>http://www.ourmysql.com/feed</fs:srcfeed><fs:itemid>feedsky/ourmysql/~7195843/620768938/5270018</fs:itemid></item><item><title>Mysql源码学习——Connection Manager</title><link>http://ourmysql.com/archives/1100</link><content:encoded>&lt;p&gt;&lt;strong&gt;1.连接的线程数&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Mysql支持单线程和多线程两种连接线程数。如果是单线程，则在同一时刻，只能有一个connection连接到Mysql，&lt;/p&gt;
&lt;p&gt;其他的连接会被挂起。如果是多线程，则同一时刻可以支持多个connection同时连接到服务器。&lt;/p&gt;
&lt;p&gt;可以通过&lt;strong&gt;设置服务器的启动参数&lt;/strong&gt;来设定连接的线程数：&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;mysqld.exe --thread-handling=no-threads
mysqld.exe --thread-handling=one-thread-per-connection&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;服务器如何通过参数来选择使用哪种方式的呢？且看服务器中的分支代码：&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;#ifdef EMBEDDED_LIBRARY
  one_thread_scheduler(&amp;amp;thread_scheduler);
#else
  if (global_system_variables.thread_handling &amp;lt;=
      SCHEDULER_ONE_THREAD_PER_CONNECTION)
    one_thread_per_connection_scheduler(&amp;amp;thread_scheduler);
  else if (global_system_variables.thread_handling == SCHEDULER_NO_THREADS)
    one_thread_scheduler(&amp;amp;thread_scheduler);
  else
    pool_of_threads_scheduler(&amp;amp;thread_scheduler);  /* purecov: tested */
#endif&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这段代码出现在get_options函数中，此函数是根据传入的服务器参数，设置相应参数的模式。由这段代码可以看出，如果定义了EMBEDDED_LIBRARY宏定义(估计应该是嵌入式使用)，则调用one_thread_scheduler，即使用单线程。如果参数小于等于SCHEDULER_ONE_THREAD_PER_CONNECTION，则调用one_thread_per_connection_scheduler，即每个连接一个线程，即多线程。 至于global_system_variables.thread_handling是如何进行设置的呢？其实就是根据我们传递给服务器的参数&amp;#8211;thread-handling进行设置的，参数的设置统一在函数get_options中，其调用mysqld_get_one_option，其中有个分支，代码如下：&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;case OPT_THREAD_HANDLING:
  {
    global_system_variables.thread_handling=
      find_type_or_exit(argument, &amp;amp;thread_handling_typelib, opt-&amp;gt;name)-1;
    break;
  }&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;对参数初始化有兴趣的可以具体的看下get_options这个函数，这里就不详细讲解了。 我们来看下one_thread_scheduler和one_thread_per_connection_scheduler的源代码，看下他们都做了些什么？&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;void one_thread_scheduler(scheduler_functions* func)
{
  func-&amp;gt;max_threads= 1;
#ifndef EMBEDDED_LIBRARY
  func-&amp;gt;add_connection= handle_connection_in_main_thread;
#endif
  func-&amp;gt;init_new_connection_thread= init_dummy;
  func-&amp;gt;end_thread= no_threads_end;
}

void one_thread_per_connection_scheduler(scheduler_functions* func)
{
  func-&amp;gt;max_threads= max_connections;
  func-&amp;gt;add_connection= create_thread_to_handle_connection;
  func-&amp;gt;end_thread= one_thread_per_connection_end;
}&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;原来就是设置了一个结构体中scheduler_functions的参数，只不过这些参数是一些函数指针罢了，也就是说在具体的调用中，&lt;/p&gt;
&lt;p&gt;只需要调用add_connection或end_thread即可，不需要知道到底是调用了哪个函数，这大概就是一种变形的多态性吧。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.初始化网络配置&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;网络配置比较简单，就是设置端口，创建套接字，绑定端口，监听端口。实现全部集中在network_init函数中，由于这个函数确&lt;/p&gt;
&lt;p&gt;实没什么好讲的，如果对socket不熟悉的话，可以去网上搜索下相关知识。这里直接给出相应的伪代码：&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;network_init
{
    set_ports; //设置端口号，#define MYSQL_PORT            3306
    socket； //创建套接字
    bind;       //绑定端口号
    listen； //监听端口号
}&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;3.连接的方式&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;进程间通信的方式不止是SOCKET，还有其他很多方式。Mysql支持三种连接方式：namepipe、socket和shared memory，&lt;/p&gt;
&lt;p&gt;即命名管道、套接字和共享内存的方式。这三种方式是可以共存的。默认只使用套接字。&lt;/p&gt;
&lt;p&gt;TCP/IP套接字方式是MySQL在任何平台下都提供的连接方式，也是网络中使用得最多的一种方式。这种方式在TCP/IP连接上建立&lt;/p&gt;
&lt;p&gt;一个基于网络的连接请求，一般情况下客户端在一台服务器上，而MySQL实例在另一台服务器上，这两台机器通过一个TCP/IP网络连接。&lt;/p&gt;
&lt;p&gt;例如，我可以在Windows服务器下请求一台远程Linux服务器下的MySQL实例。&lt;/p&gt;
&lt;p&gt;在Windows 2000、Windows XP、Windows 2003和Windows Vista以及在此之后的 Windows操作系统中，如果两个需要通&lt;/p&gt;
&lt;p&gt;信的进程在同一台服务器上，那么可以使用命名管道，SQL Server数据库默认安装后的本地连接也使用命名管道。在MySQL数据库中，&lt;/p&gt;
&lt;p&gt;需在配置文件中启用&amp;#8211;enable-named-pipe选项。在MySQL 4.1之后的版本中，MySQL还提供了共享内存的连接方式，在配置文件中&lt;/p&gt;
&lt;p&gt;添加&amp;#8211;shared-memory。如果想使用共享内存的方式，在连接时，Mysql客户端还必须使用-protocol=memory选项。&lt;/p&gt;
&lt;p&gt;启动时可以通过下面的参数进行设置。&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;mysqld.exe --enable-named-pipe
mysqld.exe --shared-memory&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;除了在启动时进行参数设置外，也可以通过修改MY.INI文件进行设置。我们来看下源码中选择连接方式的分支函数handle_connections_methods：&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;handle_connections_methods()
{
if (hPipe != INVALID_HANDLE_VALUE)
{
       handler_count++;
       if (pthread_create(&amp;amp;hThread,&amp;amp;connection_attrib,
               handle_connections_namedpipes, 0))
       {
      sql_print_warning(&quot;Can't create thread to handle named pipes&quot;);
      handler_count--;
    }
}
    if (have_tcpip &amp;amp;&amp;amp; !opt_disable_networking)
  {
    handler_count++;
    if (pthread_create(&amp;amp;hThread,&amp;amp;connection_attrib,
               handle_connections_sockets, 0))
    {
      sql_print_warning(&quot;Can't create thread to handle TCP/IP&quot;);
      handler_count--;
    }
  }

if (opt_enable_shared_memory)
  {
    handler_count++;
    if (pthread_create(&amp;amp;hThread,&amp;amp;connection_attrib,
               handle_connections_shared_memory, 0))
    {
      sql_print_warning(&quot;Can't create thread to handle shared memory&quot;);
      handler_count--;
    }
  }
}&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;由于对于namepipe和memory share的通信方式不太了解，这里只研究socket的通信方式。从代码中可以看出，handle_connections_sockets便是socket的设置，我们就来看下它。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.socket管理创建新线程&lt;/strong&gt; socket管理其实比较简单，直接给出其伪代码：&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;handle_connections_sockets
{
    select; //监视socket文件描述符
    new_socket = accept;//处理到来的客户端连接
    thd = new THD；创建THD类
    vio_tmp = vio_new(new_socket,VIO_TYPE_TCPIP, 0);   //初始化VIO结构体
    my_net_init(&amp;amp;thd-&amp;gt;net, vio_tmp);//初始化thd的net结构体
    create_new_thread(thd);//为这个连接创建一个新的线程，如果是单线程模式的话，就不会创建一个新线程
}&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;首先是select函数进行监视socket端口，如果监控到有连接，则通过accept函数接受客户端的连接，然后新建一个THD类，将连接参数全部设置到THD类的参数上，&lt;strong&gt;最后调用create_new_thread函数，这个函数便是重点&lt;/strong&gt;。 我们进入这个函数，看下做了啥。&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;create_new_thread
{
    ++connection_count;//全局连接数自增
    thread_count++;    //全局线程数自增
    thread_scheduler.add_connection(thd);//真正创建线程
}&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So easy,首先将全局连接数+1，全局线程数+1，然后调用add_connection函数，这个函数就是我们在上面第一步设置连接的&lt;/p&gt;
&lt;p&gt;线程数中，one_thread_scheduler和one_thread_per_connection_scheduler中设置的一个参数。这两者的区别便是是否创建了&lt;/p&gt;
&lt;p&gt;一个新的线程来处理到来的连接。 one_thread_scheduler是单线程方式，木有新建线程。我们重点研究 one_thread_per_connection_scheduler，其设置的add_connection函数为 create_thread_to_handle_connection：&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;create_thread_to_handle_connection(THD *thd)
{
    thread_created++;
    threads.append(thd); // 创建线程数自增，并加入到threads链表上
    pthread_create(&amp;amp;thd-&amp;gt;real_id,&amp;amp;connection_attrib,
                              handle_one_connection,
                              (void*) thd);//这就是真正创建线程的地方了，函数便是handle_one_connection
}&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;可见，最后调用了pthread_create函数，这个函数便是创建一个新的线程，新线程的处理函数为handle_one_connection.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5.新线程处理流程&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;新线程处理函数为handle_one_connection，到此位置，一个新的connection被一个新创建的线程所单独处理。我们看下其中&lt;/p&gt;
&lt;p&gt;是如何进行处理的。&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;handle_one_connection(void *arg)
{
    for (;;)
    {
        lex_start(thd); //初始化词法分析结构体
        login_connection(thd); //用户认证，失败报错
        prepare_new_connection_state(THD* thd)；//Initialize THD to handle queries
         while (!net-&amp;gt;error &amp;amp;&amp;amp; net-&amp;gt;vio != 0 &amp;amp;&amp;amp;   //循环处理command
           !(thd-&amp;gt;killed == THD::KILL_CONNECTION))
        {
            if (do_command(thd))
              break;                   //处理失败跳出
          }
          end_connection(thd);         //关闭连接
          close_connection(thd, 0, 1);
         thread_scheduler.end_thread(thd,1);//结束线程
                  return 0;
    }
}&lt;/pre&gt;
&lt;div&gt;&lt;a&gt;复制代码&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;首先进行了词法分析结构体的初始化，然后进行用户认证，认证成功后通过do_command循环执行客户端发过来的命令。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6.总结&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;整个connection manager的流程十分清晰，单线程的连接一般很少使用，大多使用多线程方式。多线程连接中其实还涉及到线程缓冲&lt;/p&gt;
&lt;p&gt;池的概念，即如果一个连接断开后，其所创建的线程不会被销毁掉，而是放到缓冲池中，等待下一个新的connection到来时，首先去线程&lt;/p&gt;
&lt;p&gt;缓冲池查找是否有空闲的线程，有的话直接使用，木有的话才去创建新的线程来管理这个connection。这些属于Thread Manage的内容，&lt;/p&gt;
&lt;p&gt;下节进行Thread Manage的学习。&lt;/p&gt;
&lt;h3  class=&quot;related_post_title&quot;&gt;相关文章&lt;/h3&gt;&lt;ul class=&quot;related_post&quot;&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1107&quot; title=&quot;Mysql源码学习——没那么简单的Hash&quot;&gt;Mysql源码学习——没那么简单的Hash&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1105&quot; title=&quot;Mysql源码学习——用户认证原理与实现&quot;&gt;Mysql源码学习——用户认证原理与实现&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1102&quot; title=&quot;Mysql源码学习——Thread Manager&quot;&gt;Mysql源码学习——Thread Manager&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1098&quot; title=&quot;Mysql源码学习——八度空间&quot;&gt;Mysql源码学习——八度空间&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1095&quot; title=&quot;Mysql源码学习——源码目录结构&quot;&gt;Mysql源码学习——源码目录结构&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1092&quot; title=&quot;Mysql源码学习——打造专属语法&quot;&gt;Mysql源码学习——打造专属语法&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1090&quot; title=&quot;Mysql源码学习——词法分析MYSQLlex&quot;&gt;Mysql源码学习——词法分析MYSQLlex&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1088&quot; title=&quot;Mysql源码学习笔记——偷窥线程&quot;&gt;Mysql源码学习笔记——偷窥线程&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1086&quot; title=&quot;Mysql的源码安装&quot;&gt;Mysql的源码安装&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1084&quot; title=&quot;MySQL源码学习——DBUG调试&quot;&gt;MySQL源码学习——DBUG调试&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
	标签：&lt;a href=&quot;http://ourmysql.com/archives/tag/connection-manager&quot; title=&quot;Connection Manager&quot; rel=&quot;tag&quot;&gt;Connection Manager&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/category/advanced&quot; title=&quot;MySQL高级应用&quot; rel=&quot;tag&quot;&gt;MySQL高级应用&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/%e6%ba%90%e7%a0%81&quot; title=&quot;源码&quot; rel=&quot;tag&quot;&gt;源码&lt;/a&gt;&lt;br /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/620768939/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1100&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://ourmysql.com/archives/1100/feed</wfw:commentRss><slash:comments>1</slash:comments><description>Mysql支持单线程和多线程两种连接线程数。如果是单线程，则在同一时刻，只能有一个connection连接到Mysql，其他的连接会被挂起。如果是多线程，则同一时刻可以支持多个connection同时连接到服务器。&lt;img src=&quot;http://www1.feedsky.com/t1/620768939/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1100&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>源码</category><category>MySQL高级应用</category><category>Connection Manager</category><pubDate>Mon, 26 Mar 2012 13:39:39 +0800</pubDate><author>OurMySQL</author><comments>http://ourmysql.com/archives/1100#comments</comments><guid isPermaLink="false">http://ourmysql.com/?p=1100</guid><dc:creator>OurMySQL</dc:creator><fs:srclink>http://ourmysql.com/archives/1100</fs:srclink><fs:srcfeed>http://www.ourmysql.com/feed</fs:srcfeed><fs:itemid>feedsky/ourmysql/~7195843/620768939/5270018</fs:itemid></item><item><title>Mysql源码学习——八度空间</title><link>http://ourmysql.com/archives/1098</link><content:encoded>&lt;div id=&quot;cnblogs_post_body&quot;&gt;
&lt;p&gt;      学习完词法分析和语法分析后，开始进入Mysql源码的正式学习之旅了。这么多模块，肿么入手呢？！还好从网上搜到了一个模块划分，以后就尽可能根据这个模块划分一步一步的跟踪源码，揭开Mysql的面纱。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;a href=&quot;http://images.cnblogs.com/cnblogs_com/nocode/201108/20110815222255206.png&quot;&gt;&lt;img title=&quot;01-1&quot; src=&quot;http://images.cnblogs.com/cnblogs_com/nocode/201108/20110815222333572.png&quot; alt=&quot;01-1&quot; width=&quot;711&quot; height=&quot;604&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;我们从上至下来看各个模块的划分，首先客户端发送请求与服务器连接，通过connection manager模块，连接管理模块会调用Thread Manager模块，即线程管理模块，这里会为一个连接创建一个新的线程，专门为这个连接服务，这就保证了每个连接都有一个独立的线程为之工作，当然连接 数一般也会有个限制，不然无限制的创建新的线程，操作系统也顶不住啊。接着进入了User Module，用户模块，这个模块应该是身份识别认证阶段，说白了就是检查用户名密码，当然应该还包括权限检查(只有自主访问控制，Mysql不像 Oracle，不支持role，更不用说label了。这就是简约而不简单吧，^_^)。&lt;/p&gt;
&lt;p&gt;上面的三个模块就是登录过程中必须经历的阶段。connection manager为客户端和服务器创建连接，thread manager为新建的连接分配一个独立的线程，user Module进行身份认证。oh yeah～～&lt;/p&gt;
&lt;p&gt;接着进入Commander Dispatcher模块，命令分发模块，大概就是一个switch case的过程，根据不同的命令，进行不同的操作。这个模块又会间接关联到Query Cache模块和Logging Module，即查询缓存模块和日志模块。Query Cache模块个人感觉至少包含结果集缓存模块，至于有木有执行计划缓存，这个就不清楚了，还需要进入源码慢慢看来。Logging Module就是传说中的日志了，日志包括redo和undo两方面吧，日志系统是一个database必备的，是实现事务特性的重要手段，而事务便是 database和file system的根本区别，不要小瞧了Logging Module啊！！&lt;/p&gt;
&lt;p&gt;命令分发模块，根据命令的性质，将命令分给不同的子模块。SELECT分配给Optimizer即优化模块，一条select语句最重要的就是执行计划 了，一个好的执行计划比一个坏的执行计划不知道要快多少倍，这就是为什么我们要建立索引，其实在经常查询的列上建立二级索引，就是为了改变执行计划，让执 行计划可以选择二级索引，而抛弃聚簇索引(当然不是完全抛弃，聚簇索引是根本)。UPDATE、INSERT、DELETE交给Table Modification Module，不看也知道，这个模块主要是处理数据更新了（这里所说的更新是指数据的改变，即UID）。Repairs分配给了Table Maintenance Module，字面意义是说表维护模块，我OUT了，默认表坏了，支持修复？是何种坏了？不太了解啊…。Replication分配给了 Replication Module，就是复制模块。最后一个是Status分配给了Status Reporting Module，这个我貌似接触过，是不是所谓的那些动态试图？比如查看系统当前状态下的锁资源的占用情况等，这个模块应该是性能分析者居家旅行必备的模块 吧，通过这个模块可能很快找到系统性能的瓶颈。&lt;/p&gt;
&lt;p&gt;上面的模块又统一走到Access Control Module，访问控制模块啊，原来上面所说的User Module不包含访问控制…，这个访问控制就是简单的DAC,即检查用户是否对要访问的对象具有增、删、改、查的权限。接着进入Table Manager模块，因为Mysql支持不同的存储引擎，而这个模块是个统一的模块，个人感觉这个应该是表的字典对象管理模块，即表的一些元数据，比如这 个表包含哪些列啊，各个列的类型，表的创建者，创建日期，表的存储引擎之类的信息。最下面是Abstract Storage Engine Module，即抽象存储引擎模块，Mysql的保持这么多存储引擎同时在服务器中，是通过一个handler抽象类实现的(不知道有木有抽象类的概念， 小弟C++、JAVA丢了很久了…)，每个存储引擎按照规定的接口，实现一个具体的handler类，然后再调用的时候，根据上面的Table Manager模块中的存储引擎的信息，选择对应的handler类进行相应表的物理操作。&lt;/p&gt;
&lt;p&gt;看了这个模块图，感觉思路清晰了很多。下面就一步一步的学习每个模块，当然这些模块之间也是一个执行流程顺序执行的过程。今天就写到这了，下次开始学习第一个模块：&lt;a href=&quot;http://ourmysql.com/archives/tag/connection-manager&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 Connection Manager 下的日志&quot;&gt;Connection Manager&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PS. 貌似最近没这么忙了，加班加了好几个月终于算是稍微轻松了一点。以后把更多的业余时间放在读书学习上。&lt;/p&gt;
&lt;p&gt;PS again. 每天下班脑子都一锅粥了，回来写点博客权当放松啦，标题的八度空间是JAY的专辑名啦，借此来比喻Mysql的各个模块^_^&lt;/p&gt;
&lt;/div&gt;
&lt;h3  class=&quot;related_post_title&quot;&gt;相关文章&lt;/h3&gt;&lt;ul class=&quot;related_post&quot;&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1107&quot; title=&quot;Mysql源码学习——没那么简单的Hash&quot;&gt;Mysql源码学习——没那么简单的Hash&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1105&quot; title=&quot;Mysql源码学习——用户认证原理与实现&quot;&gt;Mysql源码学习——用户认证原理与实现&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1102&quot; title=&quot;Mysql源码学习——Thread Manager&quot;&gt;Mysql源码学习——Thread Manager&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1100&quot; title=&quot;Mysql源码学习——Connection Manager&quot;&gt;Mysql源码学习——Connection Manager&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1095&quot; title=&quot;Mysql源码学习——源码目录结构&quot;&gt;Mysql源码学习——源码目录结构&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1092&quot; title=&quot;Mysql源码学习——打造专属语法&quot;&gt;Mysql源码学习——打造专属语法&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1090&quot; title=&quot;Mysql源码学习——词法分析MYSQLlex&quot;&gt;Mysql源码学习——词法分析MYSQLlex&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1088&quot; title=&quot;Mysql源码学习笔记——偷窥线程&quot;&gt;Mysql源码学习笔记——偷窥线程&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1086&quot; title=&quot;Mysql的源码安装&quot;&gt;Mysql的源码安装&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1084&quot; title=&quot;MySQL源码学习——DBUG调试&quot;&gt;MySQL源码学习——DBUG调试&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
	标签：&lt;a href=&quot;http://ourmysql.com/archives/category/advanced&quot; title=&quot;MySQL高级应用&quot; rel=&quot;tag&quot;&gt;MySQL高级应用&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/%e5%85%ab%e5%ba%a6%e7%a9%ba%e9%97%b4&quot; title=&quot;八度空间&quot; rel=&quot;tag&quot;&gt;八度空间&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/%e6%ba%90%e7%a0%81&quot; title=&quot;源码&quot; rel=&quot;tag&quot;&gt;源码&lt;/a&gt;&lt;br /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/620768940/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1098&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://ourmysql.com/archives/1098/feed</wfw:commentRss><slash:comments>0</slash:comments><description>我们从上至下来看各个模块的划分，首先客户端发送请求与服务器连接，通过connection manager模块，连接管理模块会调用Thread Manager模块，即线程管理模块，这里会为一个连接创建一个新的线程，专门为这个连接服务，这就保证了每个连接都有一个独立的线程为之工作，当然连接数一般也会有个限制，不然无限制的创建新的线程，操作系统也顶不住啊。接着进入了User Module，用户模块，这个模块应该是身份识别认证阶段，说白了就是检查用户名密码，当然应该还包括权限检查(只有自主访问控制，Mysql不像 Oracle，不支持role，更不用说label了。这就是简约而不简单吧，^_^)。&lt;img src=&quot;http://www1.feedsky.com/t1/620768940/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1098&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>八度空间</category><category>源码</category><category>MySQL高级应用</category><pubDate>Mon, 26 Mar 2012 13:37:49 +0800</pubDate><author>OurMySQL</author><comments>http://ourmysql.com/archives/1098#comments</comments><guid isPermaLink="false">http://ourmysql.com/?p=1098</guid><dc:creator>OurMySQL</dc:creator><fs:srclink>http://ourmysql.com/archives/1098</fs:srclink><fs:srcfeed>http://www.ourmysql.com/feed</fs:srcfeed><fs:itemid>feedsky/ourmysql/~7195843/620768940/5270018</fs:itemid></item><item><title>Mysql源码学习——源码目录结构</title><link>http://ourmysql.com/archives/1095</link><content:encoded>&lt;p&gt;目录清单&lt;/p&gt;
&lt;p&gt;目录名 注释&lt;/p&gt;
&lt;p&gt;Bdb 伯克利DB表引擎&lt;/p&gt;
&lt;p&gt;BUILD 构建工程的脚本&lt;/p&gt;
&lt;p&gt;Client 客户端&lt;/p&gt;
&lt;p&gt;Cmd-line-utils 命令行工具&lt;/p&gt;
&lt;p&gt;Config 构建工程所需的一些文件&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://ourmysql.com/archives/tag/dbug&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 DBUG 下的日志&quot;&gt;Dbug&lt;/a&gt; Fred Fish的调试库&lt;/p&gt;
&lt;p&gt;Docs 文档文件夹&lt;/p&gt;
&lt;p&gt;Extra 一些相对独立的次要的工具&lt;/p&gt;
&lt;p&gt;Heap HEAP表引擎&lt;/p&gt;
&lt;p&gt;Include 头文件&lt;/p&gt;
&lt;p&gt;Innobase INNODB表引擎&lt;/p&gt;
&lt;p&gt;Libmysql 动态库&lt;/p&gt;
&lt;p&gt;Libmysql_r 为了构建线程安全的libmysql库&lt;/p&gt;
&lt;p&gt;Libmysqld 服务器作为一个嵌入式的库&lt;/p&gt;
&lt;p&gt;Man 用户手册&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://ourmysql.com/archives/tag/myisam&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 MyISAM 下的日志&quot;&gt;Myisam&lt;/a&gt; MyISAM表引擎&lt;/p&gt;
&lt;p&gt;Myisammrg MyISAM Merge表引擎&lt;/p&gt;
&lt;p&gt;Mysql-test mysqld的测试单元&lt;/p&gt;
&lt;p&gt;Mysys MySQL的系统库&lt;/p&gt;
&lt;p&gt;Ndb Mysql集群&lt;/p&gt;
&lt;p&gt;Netware Mysql网络版本相关文件&lt;/p&gt;
&lt;p&gt;NEW-RPM 部署时存放RPM&lt;/p&gt;
&lt;p&gt;Os2 针对OS/2操作系统的底层函数&lt;/p&gt;
&lt;p&gt;Pstack 进行堆栈&lt;/p&gt;
&lt;p&gt;Regex 正则表达式库（包括扩展的正则表达式函数）&lt;/p&gt;
&lt;p&gt;SCCS 源码控制系统（不是源码的一部分）&lt;/p&gt;
&lt;p&gt;Scripts 批量SQL脚本，如初始化库脚本&lt;/p&gt;
&lt;p&gt;Server-tools 管理工具&lt;/p&gt;
&lt;p&gt;Sql 处理SQL命令；Mysql的核心&lt;/p&gt;
&lt;p&gt;Sql-bench Mysql的标准检查程序&lt;/p&gt;
&lt;p&gt;Sql-common 一些sql文件夹相关的C文件&lt;/p&gt;
&lt;p&gt;SSL 安全套接字层&lt;/p&gt;
&lt;p&gt;Strings 字符串函数库&lt;/p&gt;
&lt;p&gt;Support-files 用于在不同系统上构建Mysql的文件&lt;/p&gt;
&lt;p&gt;Tests 包含Perl和C的测试&lt;/p&gt;
&lt;p&gt;Tools&lt;/p&gt;
&lt;p&gt;Vio 虚拟I/O库&lt;/p&gt;
&lt;p&gt;Zlib 数据压缩库，用于WINDOWS&lt;/p&gt;
&lt;p&gt;下面给出几个比较重要的目录清单：&lt;/p&gt;
&lt;p&gt;文件清单&lt;/p&gt;
&lt;p&gt;目录名 文件名 注释&lt;/p&gt;
&lt;p&gt;Client&lt;/p&gt;
&lt;p&gt;get_password.c 命令行输入密码&lt;/p&gt;
&lt;p&gt;Mysql.cc MySQL命令行工具&lt;/p&gt;
&lt;p&gt;Mysqladmin.cc 数据库weihu&lt;/p&gt;
&lt;p&gt;Mysqldump.c 将表的内容以SQL语句输出，即逻辑备份&lt;/p&gt;
&lt;p&gt;Mysqlimport.c 文本文件数据导入表中&lt;/p&gt;
&lt;p&gt;Mysqlmanager-pwgen.c 密码生成&lt;/p&gt;
&lt;p&gt;Mysqlshow.c 显示数据库，表和列&lt;/p&gt;
&lt;p&gt;Mysqltest.c 被mysql测试单元使用的测试程序&lt;/p&gt;
&lt;p&gt;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;&amp;#8212;-&lt;/p&gt;
&lt;p&gt;MYSYS&lt;/p&gt;
&lt;p&gt;Array.c 动态数组&lt;/p&gt;
&lt;p&gt;Charset.c 动态字符集，默认字符集&lt;/p&gt;
&lt;p&gt;Charset-def.c 包含客户端使用的字符集&lt;/p&gt;
&lt;p&gt;Checksum.c 为内存块计算校验和，用于pack_isam&lt;/p&gt;
&lt;p&gt;Default.c 从*.cnf和*.ini文件中查找默认配置项&lt;/p&gt;
&lt;p&gt;Default_modify.c 编辑可选项&lt;/p&gt;
&lt;p&gt;Errors.c 英文错误文本&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://ourmysql.com/archives/tag/hash&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 Hash 下的日志&quot;&gt;Hash&lt;/a&gt;.c hash查找、比较、释放函数&lt;/p&gt;
&lt;p&gt;List.c 双向链表&lt;/p&gt;
&lt;p&gt;Make-conf.c 创建*.conf文件&lt;/p&gt;
&lt;p&gt;Md5.c MD5算法&lt;/p&gt;
&lt;p&gt;Mf_brkhant.c&lt;/p&gt;
&lt;p&gt;Mf_cache.c 打开临时文件,并使用io_cache进行缓存&lt;/p&gt;
&lt;p&gt;Mf_driname.c 解析，转换路径名&lt;/p&gt;
&lt;p&gt;Mf_fn_ext.c 获取文件名的后缀&lt;/p&gt;
&lt;p&gt;Mf_format.c 格式化文件名&lt;/p&gt;
&lt;p&gt;Mf_getdate 获取日期：&lt;/p&gt;
&lt;p&gt;yyyy-mm-dd hh:mm:ss format&lt;/p&gt;
&lt;p&gt;mf_iocache.c 缓存I/O&lt;/p&gt;
&lt;p&gt;mf_iocaches.c 多键值缓存&lt;/p&gt;
&lt;p&gt;mf_loadpath.c 获取全路径名&lt;/p&gt;
&lt;p&gt;mf_pack.c 创建需要的压缩/非压缩文件名&lt;/p&gt;
&lt;p&gt;mf_path.c 决定是否程序可以找到文件&lt;/p&gt;
&lt;p&gt;mf_qsort.c 快速排序&lt;/p&gt;
&lt;p&gt;mf_qsort2.c 快速排序2&lt;/p&gt;
&lt;p&gt;mf_radix.c 基数排序&lt;/p&gt;
&lt;p&gt;mf_soundex.c 探测算法（EDN NOV 14, 1985）&lt;/p&gt;
&lt;p&gt;mf_strip.c 去字符串结尾空格&lt;/p&gt;
&lt;p&gt;mf_tempdir.c 临时文件夹的创建、查找、删除&lt;/p&gt;
&lt;p&gt;mf_tempfile.c 临时文件的创建&lt;/p&gt;
&lt;p&gt;mf_unixpath.c 转化文件名为UNIX风格&lt;/p&gt;
&lt;p&gt;mf_util.c 常用函数&lt;/p&gt;
&lt;p&gt;mf_wcomp.c 使用通配符比较&lt;/p&gt;
&lt;p&gt;mf_wfile.c 通配符查找文件&lt;/p&gt;
&lt;p&gt;mulalloc.c 同时分配多个指针&lt;/p&gt;
&lt;p&gt;my_access.c 检查文件或路径是否合法&lt;/p&gt;
&lt;p&gt;my_aes.c AES加密算法&lt;/p&gt;
&lt;p&gt;my_alarm.c 警报相关&lt;/p&gt;
&lt;p&gt;my_alloc.c 同时分配临时结果集缓存&lt;/p&gt;
&lt;p&gt;my_append.c 一个文件到另一个&lt;/p&gt;
&lt;p&gt;my_bit.c 除法使用，位运算&lt;/p&gt;
&lt;p&gt;my_bitmap.c 位图&lt;/p&gt;
&lt;p&gt;my_chsize.c 填充或截断一个文件&lt;/p&gt;
&lt;p&gt;my_clock.c 时钟函数&lt;/p&gt;
&lt;p&gt;my_compress.c 压缩&lt;/p&gt;
&lt;p&gt;my_copy.c 拷贝文件&lt;/p&gt;
&lt;p&gt;my_crc32.c&lt;/p&gt;
&lt;p&gt;my_create.c 创建文件&lt;/p&gt;
&lt;p&gt;my_delete.c 删除文件&lt;/p&gt;
&lt;p&gt;my_div.c 获取文件名&lt;/p&gt;
&lt;p&gt;my_dup.c 打开复制文件&lt;/p&gt;
&lt;p&gt;my_error.c 错误码&lt;/p&gt;
&lt;p&gt;my_file.c&lt;/p&gt;
&lt;p&gt;my_fopen.c 打开文件&lt;/p&gt;
&lt;p&gt;my_fstream.c 文件流读/写&lt;/p&gt;
&lt;p&gt;my_gethostbyname.c 获取主机名&lt;/p&gt;
&lt;p&gt;my_gethwaddr.c 获取硬件地址&lt;/p&gt;
&lt;p&gt;my_getopt.c 查找生效的选项&lt;/p&gt;
&lt;p&gt;my_getsystime.c time of day&lt;/p&gt;
&lt;p&gt;my_getwd.c 获取工作目录&lt;/p&gt;
&lt;p&gt;my_handler.c&lt;/p&gt;
&lt;p&gt;my_init.c 初始化变量和函数&lt;/p&gt;
&lt;p&gt;my_largepage.c 获取OS的分页大小&lt;/p&gt;
&lt;p&gt;my_lib.c 比较/转化目录名和文件名&lt;/p&gt;
&lt;p&gt;my_lock.c 锁住文件&lt;/p&gt;
&lt;p&gt;my_lockmem.c 分配一块被锁住的内存&lt;/p&gt;
&lt;p&gt;my_lread.c 读取文件到内存&lt;/p&gt;
&lt;p&gt;my_lwrite.c 内存写入文件&lt;/p&gt;
&lt;p&gt;my_malloc.c 分配内存&lt;/p&gt;
&lt;p&gt;my_messnc.c 标准输出上输出消息&lt;/p&gt;
&lt;p&gt;my_mkdir.c 创建目录&lt;/p&gt;
&lt;p&gt;my_mmap.c 内存映射&lt;/p&gt;
&lt;p&gt;my_net.c net函数&lt;/p&gt;
&lt;p&gt;my_netware.c Mysql网络版&lt;br /&gt;
my_once.c 一次分配，永不free&lt;/p&gt;
&lt;p&gt;my_open.c 打开一个文件&lt;/p&gt;
&lt;p&gt;my_os2cond.c 操作系统cond的简单实现&lt;/p&gt;
&lt;p&gt;my_os2dirsrch.c 模拟Win32目录查询&lt;/p&gt;
&lt;p&gt;my_os2dlfcn.c 模拟UNIX动态装载&lt;/p&gt;
&lt;p&gt;my_os2file64.c 文件64位设置&lt;/p&gt;
&lt;p&gt;my_os2mutex.c 互斥量&lt;/p&gt;
&lt;p&gt;my_os2thread.c &lt;a href=&quot;http://ourmysql.com/archives/tag/%e7%ba%bf%e7%a8%8b&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 线程 下的日志&quot;&gt;线程&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;my_os2tls.c 线程本地存储&lt;/p&gt;
&lt;p&gt;my_port.c&lt;/p&gt;
&lt;p&gt;my_pthread.c 线程的封装&lt;/p&gt;
&lt;p&gt;my_quick.c 读/写&lt;/p&gt;
&lt;p&gt;my_read.c 从文件读bytes&lt;/p&gt;
&lt;p&gt;my_realloc.c 重新分配内存&lt;/p&gt;
&lt;p&gt;my_redel.c 重命名和删除文件&lt;/p&gt;
&lt;p&gt;my_seek.c 查找&lt;/p&gt;
&lt;p&gt;my_semaphore.c 信号量&lt;/p&gt;
&lt;p&gt;my_sleep.c 睡眠等待&lt;/p&gt;
&lt;p&gt;my_static.c 静态变量&lt;/p&gt;
&lt;p&gt;my_symlink.c 读取符号链接&lt;/p&gt;
&lt;p&gt;my_symlink2.c 2&lt;/p&gt;
&lt;p&gt;my_sync.c 同步内存和文件&lt;/p&gt;
&lt;p&gt;my_thr_init.c 初始化/分配线程变量&lt;/p&gt;
&lt;p&gt;my_wincond.c&lt;/p&gt;
&lt;p&gt;my_windac.c WINDOWS NT/2000自主访问控制&lt;/p&gt;
&lt;p&gt;my_winsem.c 模拟线程&lt;/p&gt;
&lt;p&gt;my_winthread.c 模拟线程&lt;/p&gt;
&lt;p&gt;my_write.c 写文件&lt;/p&gt;
&lt;p&gt;ptr_cmp.c 字节流比较函数&lt;/p&gt;
&lt;p&gt;queue,c 优先级队列&lt;/p&gt;
&lt;p&gt;raid2.c 支持RAID&lt;/p&gt;
&lt;p&gt;rijndael.c AES加密算法&lt;/p&gt;
&lt;p&gt;safemalloc.c 安全的malloc&lt;/p&gt;
&lt;p&gt;sha1.c sha1哈希加密算法&lt;/p&gt;
&lt;p&gt;string.c 字符串函数&lt;/p&gt;
&lt;p&gt;testhash.c 测试哈希函数（独立程序）&lt;/p&gt;
&lt;p&gt;test_charset 测试字符集(独立)&lt;/p&gt;
&lt;p&gt;thr_lock.c 读写锁&lt;/p&gt;
&lt;p&gt;thr_mutex.c 互斥量&lt;/p&gt;
&lt;p&gt;thr_rwlock.c 同步读写锁&lt;/p&gt;
&lt;p&gt;tree.c 二叉树&lt;/p&gt;
&lt;p&gt;typelib.c 字符串中匹配字串&lt;/p&gt;
&lt;p&gt;SQL&lt;br /&gt;
derror.cc 读取独立于语言的信息文件&lt;/p&gt;
&lt;p&gt;Des_key_file.cc 加载DES密钥&lt;/p&gt;
&lt;p&gt;Discover.cc frm文件的查找&lt;/p&gt;
&lt;p&gt;Field.cc 存储列信息&lt;/p&gt;
&lt;p&gt;Filed_conv.cc 拷贝字段信息&lt;/p&gt;
&lt;p&gt;Filesort.cc 结果集排序（内存或临时文件）&lt;/p&gt;
&lt;p&gt;Frm_crypt.cc get_crypt_from_frm&lt;/p&gt;
&lt;p&gt;Gen_&lt;a href=&quot;http://ourmysql.com/archives/tag/lex&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 LEX 下的日志&quot;&gt;lex&lt;/a&gt;_hash.cc 查找、排列SQL关键字&lt;/p&gt;
&lt;p&gt;Gstream.c GIS&lt;/p&gt;
&lt;p&gt;Handler.cc 函数句柄&lt;/p&gt;
&lt;p&gt;Hash_filo.cc 静态大小HASH表，&lt;/p&gt;
&lt;p&gt;以FIFO方式存储主机名、IP表&lt;/p&gt;
&lt;p&gt;Ha_berkeley.cc BDB的句柄&lt;/p&gt;
&lt;p&gt;Ha_&lt;a href=&quot;http://ourmysql.com/archives/tag/innodb&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 InnoDB 下的日志&quot;&gt;innodb&lt;/a&gt;.cc INNODB句柄&lt;/p&gt;
&lt;p&gt;Hostname.cc 根据IP获取hostname&lt;/p&gt;
&lt;p&gt;Init.cc 初始化和unireg相关的函数&lt;/p&gt;
&lt;p&gt;item.cc  item函数&lt;/p&gt;
&lt;p&gt;item_buff.cc item的保存和比较的缓存&lt;/p&gt;
&lt;p&gt;item_cmpfunc.cc 比较函数的定义&lt;/p&gt;
&lt;p&gt;item_create.cc 创建一个item&lt;/p&gt;
&lt;p&gt;item_func.cc 数字函数&lt;/p&gt;
&lt;p&gt;item_geofunc.cc 集合函数&lt;/p&gt;
&lt;p&gt;item_row.cc 记录项比较&lt;/p&gt;
&lt;p&gt;item_strfunc.cc 字符串函数&lt;/p&gt;
&lt;p&gt;item_subselect.cc 子查询&lt;/p&gt;
&lt;p&gt;item_sum.cc 集函数（SUM,AVG&amp;#8230;）&lt;/p&gt;
&lt;p&gt;item_timefunc.cc 时间日期函数&lt;/p&gt;
&lt;p&gt;item_uniq.cc  空文件&lt;/p&gt;
&lt;p&gt;Key.cc 创建KEY以及比较&lt;/p&gt;
&lt;p&gt;Lock.cc 锁&lt;/p&gt;
&lt;p&gt;Log.cc 日志&lt;/p&gt;
&lt;p&gt;log_event.cc 日志事件&lt;/p&gt;
&lt;p&gt;Matherr.c 处理溢出&lt;/p&gt;
&lt;p&gt;mf_iocache.cc 顺序读写的缓存&lt;/p&gt;
&lt;p&gt;Mysqld.cc main，处理信号和连接&lt;/p&gt;
&lt;p&gt;mf_&lt;a href=&quot;http://ourmysql.com/archives/tag/decimal&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 DECIMAL 下的日志&quot;&gt;decimal&lt;/a&gt;.cc decimal类型&lt;/p&gt;
&lt;p&gt;my_lock.c&lt;/p&gt;
&lt;p&gt;net_serv.cc socket数据包的解析&lt;/p&gt;
&lt;p&gt;nt_servc.cc NT服务&lt;/p&gt;
&lt;p&gt;opt_range.cc KEY排序&lt;/p&gt;
&lt;p&gt;opt_sum.cc 集函数优化&lt;/p&gt;
&lt;p&gt;parse_file.cc frm解析&lt;/p&gt;
&lt;p&gt;Password.c 密码检查&lt;/p&gt;
&lt;p&gt;Procedure.cc&lt;/p&gt;
&lt;p&gt;Protocol.cc 数据包打包发送给客户端&lt;/p&gt;
&lt;p&gt;protocol_cursor.cc 存储返送数据&lt;/p&gt;
&lt;p&gt;Records.cc 读取记录集&lt;/p&gt;
&lt;p&gt;repl_failsafe.cc&lt;/p&gt;
&lt;p&gt;set_var.cc 设置、读取用户变量&lt;/p&gt;
&lt;p&gt;Slave.cc slave节点&lt;/p&gt;
&lt;p&gt;Sp.cc 存储过程和存储函数&lt;/p&gt;
&lt;p&gt;sp_cache.cc&lt;/p&gt;
&lt;p&gt;sp_head.cc&lt;/p&gt;
&lt;p&gt;sp_pcontext.cc&lt;/p&gt;
&lt;p&gt;sp_rcontext.cc&lt;/p&gt;
&lt;p&gt;Spatial.cc 集合函数，点线面&lt;/p&gt;
&lt;p&gt;Sql_acl.cc ACL&lt;/p&gt;
&lt;p&gt;sql_analyse.cc&lt;/p&gt;
&lt;p&gt;sql_base.cc 基础函数&lt;/p&gt;
&lt;p&gt;sql_cache.cc 查询缓存&lt;/p&gt;
&lt;p&gt;sql_client.cc&lt;/p&gt;
&lt;p&gt;sql_crypt.cc 加解密&lt;/p&gt;
&lt;p&gt;sql_db.cc 创建、删除DB&lt;/p&gt;
&lt;p&gt;sql_delete.cc DELETE语句&lt;/p&gt;
&lt;p&gt;sql_derived.cc 派生表&lt;/p&gt;
&lt;p&gt;sql_do.cc DO&lt;/p&gt;
&lt;p&gt;sql_error.cc  错误和警告&lt;/p&gt;
&lt;p&gt;sql_handler.cc&lt;/p&gt;
&lt;p&gt;sql_help.cc HELP&lt;/p&gt;
&lt;p&gt;sql_insert.cc INSERT&lt;/p&gt;
&lt;p&gt;sql_lex.cc &lt;a href=&quot;http://ourmysql.com/archives/tag/%e8%af%8d%e6%b3%95%e5%88%86%e6%9e%90&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 词法分析 下的日志&quot;&gt;词法分析&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;sql_list.cc&lt;/p&gt;
&lt;p&gt;sql_load.cc LOAD DATA 语句&lt;/p&gt;
&lt;p&gt;sql_manager.cc 维护工作&lt;/p&gt;
&lt;p&gt;sql_map.cc  内存映射&lt;/p&gt;
&lt;p&gt;sql_olap.cc&lt;/p&gt;
&lt;p&gt;sql_parse.cc 解析语句&lt;/p&gt;
&lt;p&gt;sql_prepare.cc&lt;/p&gt;
&lt;p&gt;sql_rename.cc 重命名table名&lt;/p&gt;
&lt;p&gt;sql_repl.cc 复制&lt;/p&gt;
&lt;p&gt;sql_select.cc SELECT和JOIN优化&lt;/p&gt;
&lt;p&gt;sql_show.cc SHOW&lt;/p&gt;
&lt;p&gt;sql_state.c 错误号和状态的映射&lt;/p&gt;
&lt;p&gt;sql_string.cc&lt;/p&gt;
&lt;p&gt;sql_table.cc DROP TABLE、ALTER TABLE&lt;/p&gt;
&lt;p&gt;sql_trigger.cc 触发器&lt;/p&gt;
&lt;p&gt;sql_udf.cc 用户自定义函数&lt;/p&gt;
&lt;p&gt;sql_union.cc UNION操作符&lt;/p&gt;
&lt;p&gt;sql_update.cc UPDATE&lt;/p&gt;
&lt;p&gt;sql_view.cc 视图&lt;/p&gt;
&lt;p&gt;Stacktrace.c 显示堆栈（LINUX/INTEL ONLY）&lt;/p&gt;
&lt;p&gt;Strfunc.cc&lt;/p&gt;
&lt;p&gt;Table.cc 表元数据获取（FRM）&lt;/p&gt;
&lt;p&gt;thr_malloc.cc&lt;/p&gt;
&lt;p&gt;Time.cc&lt;/p&gt;
&lt;p&gt;Uniques.cc 副本的快速删除&lt;/p&gt;
&lt;p&gt;Unireg.cc 创建一个FRM&lt;/p&gt;
&lt;p&gt;更多内容请参考：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://forge.mysql.com/wiki/MySQL_Internals_Files_In_MySQL_Sources#The_sql_Directory&quot;&gt;http://forge.mysql.com/wiki/MySQL_Internals_Files_In_MySQL_Sources#The_sql_Directory&lt;/a&gt;&lt;/p&gt;
&lt;h3  class=&quot;related_post_title&quot;&gt;相关文章&lt;/h3&gt;&lt;ul class=&quot;related_post&quot;&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1107&quot; title=&quot;Mysql源码学习——没那么简单的Hash&quot;&gt;Mysql源码学习——没那么简单的Hash&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1105&quot; title=&quot;Mysql源码学习——用户认证原理与实现&quot;&gt;Mysql源码学习——用户认证原理与实现&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1102&quot; title=&quot;Mysql源码学习——Thread Manager&quot;&gt;Mysql源码学习——Thread Manager&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1100&quot; title=&quot;Mysql源码学习——Connection Manager&quot;&gt;Mysql源码学习——Connection Manager&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1098&quot; title=&quot;Mysql源码学习——八度空间&quot;&gt;Mysql源码学习——八度空间&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1092&quot; title=&quot;Mysql源码学习——打造专属语法&quot;&gt;Mysql源码学习——打造专属语法&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1090&quot; title=&quot;Mysql源码学习——词法分析MYSQLlex&quot;&gt;Mysql源码学习——词法分析MYSQLlex&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1088&quot; title=&quot;Mysql源码学习笔记——偷窥线程&quot;&gt;Mysql源码学习笔记——偷窥线程&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1086&quot; title=&quot;Mysql的源码安装&quot;&gt;Mysql的源码安装&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1084&quot; title=&quot;MySQL源码学习——DBUG调试&quot;&gt;MySQL源码学习——DBUG调试&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
	标签：&lt;a href=&quot;http://ourmysql.com/archives/category/advanced&quot; title=&quot;MySQL高级应用&quot; rel=&quot;tag&quot;&gt;MySQL高级应用&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/%e6%ba%90%e7%a0%81&quot; title=&quot;源码&quot; rel=&quot;tag&quot;&gt;源码&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/%e7%9b%ae%e5%bd%95%e7%bb%93%e6%9e%84&quot; title=&quot;目录结构&quot; rel=&quot;tag&quot;&gt;目录结构&lt;/a&gt;&lt;br /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/620768941/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1095&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://ourmysql.com/archives/1095/feed</wfw:commentRss><slash:comments>0</slash:comments><description>Mysql源码学习——源码目录结构&lt;img src=&quot;http://www1.feedsky.com/t1/620768941/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1095&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>源码</category><category>目录结构</category><category>MySQL高级应用</category><pubDate>Mon, 26 Mar 2012 13:36:24 +0800</pubDate><author>OurMySQL</author><comments>http://ourmysql.com/archives/1095#comments</comments><guid isPermaLink="false">http://ourmysql.com/?p=1095</guid><dc:creator>OurMySQL</dc:creator><fs:srclink>http://ourmysql.com/archives/1095</fs:srclink><fs:srcfeed>http://www.ourmysql.com/feed</fs:srcfeed><fs:itemid>feedsky/ourmysql/~7195843/620768941/5270018</fs:itemid></item><item><title>Mysql源码学习——打造专属语法</title><link>http://ourmysql.com/archives/1092</link><content:encoded>&lt;p&gt;接触过SQL语句的人都会看过这家或者那家的SQL手册，其语法标准应该是从SQL92开始吧，在看SQL92标准的时候，你会发现里面定义的都是一些巴 科斯范式(BNF)，就是一种语法定义的标准。不管是牛X哄哄的ORACLE，还是不幸被其收购的Mysql，都会遵循里面的标准语法，当然一些扩展的语 法除外，比如今天我们就会扩展一个简单的语法^-^。&lt;/p&gt;
&lt;p align=&quot;left&quot;&gt;         OK，大家知道了SQL语法的来源，那么如何进行语法解析呢？&lt;a href=&quot;http://ourmysql.com/archives/tag/yacc&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 YACC 下的日志&quot;&gt;YACC&lt;/a&gt;！！(Yet Another Compiler Compiler)，它的书写方式便是BNF，语法解析的利器。YACC接收来自词法分析阶段分解出来的token，然后去匹配那些BNF。今天哥就来揭 开它的面纱。（关于YACC的基本使用方法，大家可以看我上一篇中提到IBM的链接，一定要看懂那个先）&lt;/p&gt;
&lt;p align=&quot;left&quot;&gt;         继续上一节的语句SELECT @@VERSION_COMMET,为了简单，这里省去后缀limit 1。Mysql的语法文件是sql_yacc.yy,首先给出这条语句涉及到的语法节点（大体浏览下即可）:&lt;/p&gt;
&lt;blockquote&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_672907&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;div&gt;4&lt;/div&gt;
&lt;div&gt;5&lt;/div&gt;
&lt;div&gt;6&lt;/div&gt;
&lt;div&gt;7&lt;/div&gt;
&lt;div&gt;8&lt;/div&gt;
&lt;div&gt;9&lt;/div&gt;
&lt;div&gt;10&lt;/div&gt;
&lt;div&gt;11&lt;/div&gt;
&lt;div&gt;12&lt;/div&gt;
&lt;div&gt;13&lt;/div&gt;
&lt;div&gt;14&lt;/div&gt;
&lt;div&gt;15&lt;/div&gt;
&lt;div&gt;16&lt;/div&gt;
&lt;div&gt;17&lt;/div&gt;
&lt;div&gt;18&lt;/div&gt;
&lt;div&gt;19&lt;/div&gt;
&lt;div&gt;20&lt;/div&gt;
&lt;div&gt;21&lt;/div&gt;
&lt;div&gt;22&lt;/div&gt;
&lt;div&gt;23&lt;/div&gt;
&lt;div&gt;24&lt;/div&gt;
&lt;div&gt;25&lt;/div&gt;
&lt;div&gt;26&lt;/div&gt;
&lt;div&gt;27&lt;/div&gt;
&lt;div&gt;28&lt;/div&gt;
&lt;div&gt;29&lt;/div&gt;
&lt;div&gt;30&lt;/div&gt;
&lt;div&gt;31&lt;/div&gt;
&lt;div&gt;32&lt;/div&gt;
&lt;div&gt;33&lt;/div&gt;
&lt;div&gt;34&lt;/div&gt;
&lt;div&gt;35&lt;/div&gt;
&lt;div&gt;36&lt;/div&gt;
&lt;div&gt;37&lt;/div&gt;
&lt;div&gt;38&lt;/div&gt;
&lt;div&gt;39&lt;/div&gt;
&lt;div&gt;40&lt;/div&gt;
&lt;div&gt;41&lt;/div&gt;
&lt;div&gt;42&lt;/div&gt;
&lt;div&gt;43&lt;/div&gt;
&lt;div&gt;44&lt;/div&gt;
&lt;div&gt;45&lt;/div&gt;
&lt;div&gt;46&lt;/div&gt;
&lt;div&gt;47&lt;/div&gt;
&lt;div&gt;48&lt;/div&gt;
&lt;div&gt;49&lt;/div&gt;
&lt;div&gt;50&lt;/div&gt;
&lt;div&gt;51&lt;/div&gt;
&lt;div&gt;52&lt;/div&gt;
&lt;div&gt;53&lt;/div&gt;
&lt;div&gt;54&lt;/div&gt;
&lt;div&gt;55&lt;/div&gt;
&lt;div&gt;56&lt;/div&gt;
&lt;div&gt;57&lt;/div&gt;
&lt;div&gt;58&lt;/div&gt;
&lt;div&gt;59&lt;/div&gt;
&lt;div&gt;60&lt;/div&gt;
&lt;div&gt;61&lt;/div&gt;
&lt;div&gt;62&lt;/div&gt;
&lt;div&gt;63&lt;/div&gt;
&lt;div&gt;64&lt;/div&gt;
&lt;div&gt;65&lt;/div&gt;
&lt;div&gt;66&lt;/div&gt;
&lt;div&gt;67&lt;/div&gt;
&lt;div&gt;68&lt;/div&gt;
&lt;div&gt;69&lt;/div&gt;
&lt;div&gt;70&lt;/div&gt;
&lt;div&gt;71&lt;/div&gt;
&lt;div&gt;72&lt;/div&gt;
&lt;div&gt;73&lt;/div&gt;
&lt;div&gt;74&lt;/div&gt;
&lt;div&gt;75&lt;/div&gt;
&lt;div&gt;76&lt;/div&gt;
&lt;div&gt;77&lt;/div&gt;
&lt;div&gt;78&lt;/div&gt;
&lt;div&gt;79&lt;/div&gt;
&lt;div&gt;80&lt;/div&gt;
&lt;div&gt;81&lt;/div&gt;
&lt;div&gt;82&lt;/div&gt;
&lt;div&gt;83&lt;/div&gt;
&lt;div&gt;84&lt;/div&gt;
&lt;div&gt;85&lt;/div&gt;
&lt;div&gt;86&lt;/div&gt;
&lt;div&gt;87&lt;/div&gt;
&lt;div&gt;88&lt;/div&gt;
&lt;div&gt;89&lt;/div&gt;
&lt;div&gt;90&lt;/div&gt;
&lt;div&gt;91&lt;/div&gt;
&lt;div&gt;92&lt;/div&gt;
&lt;div&gt;93&lt;/div&gt;
&lt;div&gt;94&lt;/div&gt;
&lt;div&gt;95&lt;/div&gt;
&lt;div&gt;96&lt;/div&gt;
&lt;div&gt;97&lt;/div&gt;
&lt;div&gt;98&lt;/div&gt;
&lt;div&gt;99&lt;/div&gt;
&lt;div&gt;100&lt;/div&gt;
&lt;div&gt;101&lt;/div&gt;
&lt;div&gt;102&lt;/div&gt;
&lt;div&gt;103&lt;/div&gt;
&lt;div&gt;104&lt;/div&gt;
&lt;div&gt;105&lt;/div&gt;
&lt;div&gt;106&lt;/div&gt;
&lt;div&gt;107&lt;/div&gt;
&lt;div&gt;108&lt;/div&gt;
&lt;div&gt;109&lt;/div&gt;
&lt;div&gt;110&lt;/div&gt;
&lt;div&gt;111&lt;/div&gt;
&lt;div&gt;112&lt;/div&gt;
&lt;div&gt;113&lt;/div&gt;
&lt;div&gt;114&lt;/div&gt;
&lt;div&gt;115&lt;/div&gt;
&lt;div&gt;116&lt;/div&gt;
&lt;div&gt;117&lt;/div&gt;
&lt;div&gt;118&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;query:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;END_OF_INPUT&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{...}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;|| verb_clause&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{...}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;| verb_clause END_OF_INPUT&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;/* Single query, not terminated. */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;YYLIP-&amp;gt;found_semicolon= NULL;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;verb_clause:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;statement&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| begin&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;statement:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;alter&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| analyze&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| backup&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| binlog_base64_event&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| call&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| change&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| check&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| checksum&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| commit&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| create&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| deallocate&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| &lt;/code&gt;&lt;code&gt;delete&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| describe&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| &lt;/code&gt;&lt;code&gt;do&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| drop&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| execute&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| flush&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| grant&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| handler&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| help&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| insert&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| install&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| kill&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| load&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| lock&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| optimize&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| keycache&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| partition_entry&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| preload&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| prepare&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| purge&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| release&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| &lt;/code&gt;&lt;code&gt;rename&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| repair&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| replace&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| reset&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| restore&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| revoke&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| rollback&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| savepoint&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| select&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| set&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| show&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| slave&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| start&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| truncate&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| uninstall&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| unlock&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| update&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| use&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| xa&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;select:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;select_init&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;&lt;a href=&quot;http://ourmysql.com/archives/tag/lex&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 LEX 下的日志&quot;&gt;LEX&lt;/a&gt; *&lt;a href=&quot;http://ourmysql.com/archives/tag/lex&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 LEX 下的日志&quot;&gt;lex&lt;/a&gt;= &lt;a href=&quot;http://ourmysql.com/archives/tag/lex&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 LEX 下的日志&quot;&gt;Lex&lt;/a&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;lex-&amp;gt;sql_command= SQLCOM_SELECT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;select_init:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;SELECT_SYM select_init2&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| &lt;/code&gt;&lt;code&gt;'('&lt;/code&gt; &lt;code&gt;select_paren &lt;/code&gt;&lt;code&gt;')'&lt;/code&gt; &lt;code&gt;union_opt&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;select_init2:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;select_part2&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;LEX *lex= Lex;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;SELECT_LEX * sel= lex-&amp;gt;current_select;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(lex-&amp;gt;current_select-&amp;gt;set_braces(0))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;my_parse_error(ER(ER_SYNTAX_ERROR));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(sel-&amp;gt;linkage == UNION_TYPE &amp;amp;&amp;amp;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;sel-&amp;gt;master_unit()-&amp;gt;first_select()-&amp;gt;braces)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;my_parse_error(ER(ER_SYNTAX_ERROR));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;union_clause&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;select_part2:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;LEX *lex= Lex;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;SELECT_LEX *sel= lex-&amp;gt;current_select;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(sel-&amp;gt;linkage != UNION_TYPE)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;mysql_init_select(lex);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;lex-&amp;gt;current_select-&amp;gt;parsing_place= SELECT_LIST;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;select_options select_item_list&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;Select-&amp;gt;parsing_place= NO_MATTER;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;select_into select_lock_type&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_892832&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;div&gt;4&lt;/div&gt;
&lt;div&gt;5&lt;/div&gt;
&lt;div&gt;6&lt;/div&gt;
&lt;div&gt;7&lt;/div&gt;
&lt;div&gt;8&lt;/div&gt;
&lt;div&gt;9&lt;/div&gt;
&lt;div&gt;10&lt;/div&gt;
&lt;div&gt;11&lt;/div&gt;
&lt;div&gt;12&lt;/div&gt;
&lt;div&gt;13&lt;/div&gt;
&lt;div&gt;14&lt;/div&gt;
&lt;div&gt;15&lt;/div&gt;
&lt;div&gt;16&lt;/div&gt;
&lt;div&gt;17&lt;/div&gt;
&lt;div&gt;18&lt;/div&gt;
&lt;div&gt;19&lt;/div&gt;
&lt;div&gt;20&lt;/div&gt;
&lt;div&gt;21&lt;/div&gt;
&lt;div&gt;22&lt;/div&gt;
&lt;div&gt;23&lt;/div&gt;
&lt;div&gt;24&lt;/div&gt;
&lt;div&gt;25&lt;/div&gt;
&lt;div&gt;26&lt;/div&gt;
&lt;div&gt;27&lt;/div&gt;
&lt;div&gt;28&lt;/div&gt;
&lt;div&gt;29&lt;/div&gt;
&lt;div&gt;30&lt;/div&gt;
&lt;div&gt;31&lt;/div&gt;
&lt;div&gt;32&lt;/div&gt;
&lt;div&gt;33&lt;/div&gt;
&lt;div&gt;34&lt;/div&gt;
&lt;div&gt;35&lt;/div&gt;
&lt;div&gt;36&lt;/div&gt;
&lt;div&gt;37&lt;/div&gt;
&lt;div&gt;38&lt;/div&gt;
&lt;div&gt;39&lt;/div&gt;
&lt;div&gt;40&lt;/div&gt;
&lt;div&gt;41&lt;/div&gt;
&lt;div&gt;42&lt;/div&gt;
&lt;div&gt;43&lt;/div&gt;
&lt;div&gt;44&lt;/div&gt;
&lt;div&gt;45&lt;/div&gt;
&lt;div&gt;46&lt;/div&gt;
&lt;div&gt;47&lt;/div&gt;
&lt;div&gt;48&lt;/div&gt;
&lt;div&gt;49&lt;/div&gt;
&lt;div&gt;50&lt;/div&gt;
&lt;div&gt;51&lt;/div&gt;
&lt;div&gt;52&lt;/div&gt;
&lt;div&gt;53&lt;/div&gt;
&lt;div&gt;54&lt;/div&gt;
&lt;div&gt;55&lt;/div&gt;
&lt;div&gt;56&lt;/div&gt;
&lt;div&gt;57&lt;/div&gt;
&lt;div&gt;58&lt;/div&gt;
&lt;div&gt;59&lt;/div&gt;
&lt;div&gt;60&lt;/div&gt;
&lt;div&gt;61&lt;/div&gt;
&lt;div&gt;62&lt;/div&gt;
&lt;div&gt;63&lt;/div&gt;
&lt;div&gt;64&lt;/div&gt;
&lt;div&gt;65&lt;/div&gt;
&lt;div&gt;66&lt;/div&gt;
&lt;div&gt;67&lt;/div&gt;
&lt;div&gt;68&lt;/div&gt;
&lt;div&gt;69&lt;/div&gt;
&lt;div&gt;70&lt;/div&gt;
&lt;div&gt;71&lt;/div&gt;
&lt;div&gt;72&lt;/div&gt;
&lt;div&gt;73&lt;/div&gt;
&lt;div&gt;74&lt;/div&gt;
&lt;div&gt;75&lt;/div&gt;
&lt;div&gt;76&lt;/div&gt;
&lt;div&gt;77&lt;/div&gt;
&lt;div&gt;78&lt;/div&gt;
&lt;div&gt;79&lt;/div&gt;
&lt;div&gt;80&lt;/div&gt;
&lt;div&gt;81&lt;/div&gt;
&lt;div&gt;82&lt;/div&gt;
&lt;div&gt;83&lt;/div&gt;
&lt;div&gt;84&lt;/div&gt;
&lt;div&gt;85&lt;/div&gt;
&lt;div&gt;86&lt;/div&gt;
&lt;div&gt;87&lt;/div&gt;
&lt;div&gt;88&lt;/div&gt;
&lt;div&gt;89&lt;/div&gt;
&lt;div&gt;90&lt;/div&gt;
&lt;div&gt;91&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;select_item_list:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;select_item_list &lt;/code&gt;&lt;code&gt;','&lt;/code&gt; &lt;code&gt;select_item&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| select_item&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| &lt;/code&gt;&lt;code&gt;'*'&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;THD *thd= YYTHD;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;Item *item= &lt;/code&gt;&lt;code&gt;new&lt;/code&gt; &lt;code&gt;(thd-&amp;gt;mem_root)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                          &lt;/code&gt;&lt;code&gt;Item_field(&amp;amp;thd-&amp;gt;lex-&amp;gt;current_select-&amp;gt;context,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                                     &lt;/code&gt;&lt;code&gt;NULL, NULL, &lt;/code&gt;&lt;code&gt;&quot;*&quot;&lt;/code&gt;&lt;code&gt;);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(item == NULL)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(add_item_to_list(thd, item))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;(thd-&amp;gt;lex-&amp;gt;current_select-&amp;gt;with_wild)++;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;select_item:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;remember_name select_item2 remember_end select_alias&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;THD *thd= YYTHD;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;&lt;a href=&quot;http://ourmysql.com/archives/tag/dbug&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 DBUG 下的日志&quot;&gt;DBUG&lt;/a&gt;_ASSERT($1 &amp;lt; $3);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(add_item_to_list(thd, $2))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;($4.str)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(Lex-&amp;gt;sql_command == SQLCOM_CREATE_VIEW &amp;amp;&amp;amp;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                  &lt;/code&gt;&lt;code&gt;check_column_name($4.str))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;my_error(ER_WRONG_COLUMN_NAME, MYF(0), $4.str);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;$2-&amp;gt;is_autogenerated_name= FALSE;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;$2-&amp;gt;set_name($4.str, $4.length, system_charset_info);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;else&lt;/code&gt; &lt;code&gt;if&lt;/code&gt; &lt;code&gt;(!$2-&amp;gt;name)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;$2-&amp;gt;set_name($1, (uint) ($3 - $1), thd-&amp;gt;charset());&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;variable:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;'@'&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(! Lex-&amp;gt;parsing_options.allows_variable)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;variable_aux&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;$$= $3;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;variable_aux:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;ident_or_text SET_VAR expr&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;Item_func_set_user_var *item;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;$$= item= &lt;/code&gt;&lt;code&gt;new&lt;/code&gt; &lt;code&gt;(YYTHD-&amp;gt;mem_root) Item_func_set_user_var($1, $3);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;($$ == NULL)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;LEX *lex= Lex;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;lex-&amp;gt;uncacheable(UNCACHEABLE_RAND);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;lex-&amp;gt;set_var_list.push_back(item);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| ident_or_text&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;$$= &lt;/code&gt;&lt;code&gt;new&lt;/code&gt; &lt;code&gt;(YYTHD-&amp;gt;mem_root) Item_func_get_user_var($1);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;($$ == NULL)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;LEX *lex= Lex;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;lex-&amp;gt;uncacheable(UNCACHEABLE_RAND);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;| &lt;/code&gt;&lt;code&gt;'@'&lt;/code&gt; &lt;code&gt;opt_var_ident_type ident_or_text opt_component&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;/* disallow &quot;SELECT @@global.global.variable&quot; */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;($3.str &amp;amp;&amp;amp; $4.str &amp;amp;&amp;amp; check_reserved_words(&amp;amp;$3))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;my_parse_error(ER(ER_SYNTAX_ERROR));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(!($$= get_system_var(YYTHD, $2, $3, $4)))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(!((Item_func_get_system_var*) $$)-&amp;gt;is_written_to_binlog())&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;Lex-&amp;gt;set_stmt_unsafe();&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;下面我们仔细的来看一下整个SELECT语法节点的执行流程：&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_182877&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;query-&amp;gt;verb_clause-&amp;gt;statement-&amp;gt;select-&amp;gt;select_init-&amp;gt;select_init2-&amp;gt;select_part2-&amp;gt;select_item_list-&amp;gt;select_item…-&amp;gt;variable&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;语法是自上而下的，实际的解析过程是自下而上的匹配过程。词法分析首先yacc送来SELECT关键字，上一节说过为什么SELECT是关键字呢？&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;我们看下sql_yacc.yy，可以找到如下一个定义：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_367345&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;%token  SELECT_SYM                    &lt;/code&gt;&lt;code&gt;/* SQL-2003-R */&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这里其实是定义了一个宏SELECT_SYM，代表一个关键字，宏定义如下：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_465497&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;#define SELECT_SYM 687&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;那么字符串”SELECT”和SELECT_SYM是如何联系在一起的呢？我们回头看下MYSQLlex中的find_keyword这个函数：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_269430&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;div&gt;4&lt;/div&gt;
&lt;div&gt;5&lt;/div&gt;
&lt;div&gt;6&lt;/div&gt;
&lt;div&gt;7&lt;/div&gt;
&lt;div&gt;8&lt;/div&gt;
&lt;div&gt;9&lt;/div&gt;
&lt;div&gt;10&lt;/div&gt;
&lt;div&gt;11&lt;/div&gt;
&lt;div&gt;12&lt;/div&gt;
&lt;div&gt;13&lt;/div&gt;
&lt;div&gt;14&lt;/div&gt;
&lt;div&gt;15&lt;/div&gt;
&lt;div&gt;16&lt;/div&gt;
&lt;div&gt;17&lt;/div&gt;
&lt;div&gt;18&lt;/div&gt;
&lt;div&gt;19&lt;/div&gt;
&lt;div&gt;20&lt;/div&gt;
&lt;div&gt;21&lt;/div&gt;
&lt;div&gt;22&lt;/div&gt;
&lt;div&gt;23&lt;/div&gt;
&lt;div&gt;24&lt;/div&gt;
&lt;div&gt;25&lt;/div&gt;
&lt;div&gt;26&lt;/div&gt;
&lt;div&gt;27&lt;/div&gt;
&lt;div&gt;28&lt;/div&gt;
&lt;div&gt;29&lt;/div&gt;
&lt;div&gt;30&lt;/div&gt;
&lt;div&gt;31&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;static&lt;/code&gt; &lt;code&gt;int&lt;/code&gt; &lt;code&gt;find_keyword(Lex_input_stream *lip, uint len, &lt;/code&gt;&lt;code&gt;bool&lt;/code&gt; &lt;code&gt;function)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;const&lt;/code&gt; &lt;code&gt;char&lt;/code&gt; &lt;code&gt;*tok= lip-&amp;gt;get_tok_start();&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;SYMBOL *symbol= get_&lt;a href=&quot;http://ourmysql.com/archives/tag/hash&quot; class=&quot;st_tag internal_tag&quot; rel=&quot;tag&quot; title=&quot;标签 Hash 下的日志&quot;&gt;hash&lt;/a&gt;_symbol(tok, len, function);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(symbol)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;lip-&amp;gt;yylval-&amp;gt;symbol.symbol=symbol;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;lip-&amp;gt;yylval-&amp;gt;symbol.str= (&lt;/code&gt;&lt;code&gt;char&lt;/code&gt;&lt;code&gt;*) tok;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;lip-&amp;gt;yylval-&amp;gt;symbol.length=len;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;((symbol-&amp;gt;tok == NOT_SYM) &amp;amp;&amp;amp;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;(lip-&amp;gt;m_thd-&amp;gt;variables.sql_mode &amp;amp; MODE_HIGH_NOT_PRECEDENCE))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;NOT2_SYM;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;((symbol-&amp;gt;tok == OR_OR_SYM) &amp;amp;&amp;amp;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;!(lip-&amp;gt;m_thd-&amp;gt;variables.sql_mode &amp;amp; MODE_PIPES_AS_CONCAT))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;OR2_SYM;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;symbol-&amp;gt;tok;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;static&lt;/code&gt; &lt;code&gt;SYMBOL *get_hash_symbol(&lt;/code&gt;&lt;code&gt;const&lt;/code&gt; &lt;code&gt;char&lt;/code&gt; &lt;code&gt;*s,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                               &lt;/code&gt;&lt;code&gt;unsigned &lt;/code&gt;&lt;code&gt;int&lt;/code&gt; &lt;code&gt;len,&lt;/code&gt;&lt;code&gt;bool&lt;/code&gt; &lt;code&gt;function)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;register&lt;/code&gt; &lt;code&gt;uchar *hash_map;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;register&lt;/code&gt; &lt;code&gt;const&lt;/code&gt; &lt;code&gt;char&lt;/code&gt; &lt;code&gt;*cur_str= s;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(len == 0) {&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;DBUG_PRINT(&lt;/code&gt;&lt;code&gt;&quot;warning&quot;&lt;/code&gt;&lt;code&gt;, (&lt;/code&gt;&lt;code&gt;&quot;get_hash_symbol() received a request for a zero-length symbol, which is probably a mistake.&quot;&lt;/code&gt;&lt;code&gt;));&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_300472&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;div&gt;4&lt;/div&gt;
&lt;div&gt;5&lt;/div&gt;
&lt;div&gt;6&lt;/div&gt;
&lt;div&gt;7&lt;/div&gt;
&lt;div&gt;8&lt;/div&gt;
&lt;div&gt;9&lt;/div&gt;
&lt;div&gt;10&lt;/div&gt;
&lt;div&gt;11&lt;/div&gt;
&lt;div&gt;12&lt;/div&gt;
&lt;div&gt;13&lt;/div&gt;
&lt;div&gt;14&lt;/div&gt;
&lt;div&gt;15&lt;/div&gt;
&lt;div&gt;16&lt;/div&gt;
&lt;div&gt;17&lt;/div&gt;
&lt;div&gt;18&lt;/div&gt;
&lt;div&gt;19&lt;/div&gt;
&lt;div&gt;20&lt;/div&gt;
&lt;div&gt;21&lt;/div&gt;
&lt;div&gt;22&lt;/div&gt;
&lt;div&gt;23&lt;/div&gt;
&lt;div&gt;24&lt;/div&gt;
&lt;div&gt;25&lt;/div&gt;
&lt;div&gt;26&lt;/div&gt;
&lt;div&gt;27&lt;/div&gt;
&lt;div&gt;28&lt;/div&gt;
&lt;div&gt;29&lt;/div&gt;
&lt;div&gt;30&lt;/div&gt;
&lt;div&gt;31&lt;/div&gt;
&lt;div&gt;32&lt;/div&gt;
&lt;div&gt;33&lt;/div&gt;
&lt;div&gt;34&lt;/div&gt;
&lt;div&gt;35&lt;/div&gt;
&lt;div&gt;36&lt;/div&gt;
&lt;div&gt;37&lt;/div&gt;
&lt;div&gt;38&lt;/div&gt;
&lt;div&gt;39&lt;/div&gt;
&lt;div&gt;40&lt;/div&gt;
&lt;div&gt;41&lt;/div&gt;
&lt;div&gt;42&lt;/div&gt;
&lt;div&gt;43&lt;/div&gt;
&lt;div&gt;44&lt;/div&gt;
&lt;div&gt;45&lt;/div&gt;
&lt;div&gt;46&lt;/div&gt;
&lt;div&gt;47&lt;/div&gt;
&lt;div&gt;48&lt;/div&gt;
&lt;div&gt;49&lt;/div&gt;
&lt;div&gt;50&lt;/div&gt;
&lt;div&gt;51&lt;/div&gt;
&lt;div&gt;52&lt;/div&gt;
&lt;div&gt;53&lt;/div&gt;
&lt;div&gt;54&lt;/div&gt;
&lt;div&gt;55&lt;/div&gt;
&lt;div&gt;56&lt;/div&gt;
&lt;div&gt;57&lt;/div&gt;
&lt;div&gt;58&lt;/div&gt;
&lt;div&gt;59&lt;/div&gt;
&lt;div&gt;60&lt;/div&gt;
&lt;div&gt;61&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;return&lt;/code&gt;&lt;code&gt;(NULL);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(function){&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(len&amp;gt;sql_functions_max_len) &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;hash_map= sql_functions_map;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;register&lt;/code&gt; &lt;code&gt;uint32 cur_struct= uint4korr(hash_map+((len-1)*4));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;for&lt;/code&gt; &lt;code&gt;(;;){&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;register&lt;/code&gt; &lt;code&gt;uchar first_char= (uchar)cur_struct;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(first_char == 0)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;register&lt;/code&gt; &lt;code&gt;int16 ires= (int16)(cur_struct&amp;gt;&amp;gt;16);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(ires==array_elements(symbols)) &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;register&lt;/code&gt; &lt;code&gt;SYMBOL *res;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(ires&amp;gt;=0) &lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;res= symbols+ires;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;else&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;res= sql_functions-ires-1;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;register&lt;/code&gt; &lt;code&gt;uint count= (uint) (cur_str - s);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;lex_casecmp(cur_str,res-&amp;gt;name+count,len-count) ? 0 : res;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;register&lt;/code&gt; &lt;code&gt;uchar cur_char= (uchar)to_upper_lex[(uchar)*cur_str];&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(cur_char&amp;lt;first_char) &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;cur_struct&amp;gt;&amp;gt;=8;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(cur_char&amp;gt;(uchar)cur_struct) &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;cur_struct&amp;gt;&amp;gt;=8;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;cur_struct= uint4korr(hash_map+&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;(((uint16)cur_struct + cur_char - first_char)*4));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;cur_str++;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;code&gt;else&lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(len&amp;gt;symbols_max_len) &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;hash_map= symbols_map;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;register&lt;/code&gt; &lt;code&gt;uint32 cur_struct= uint4korr(hash_map+((len-1)*4));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;for&lt;/code&gt; &lt;code&gt;(;;){&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;register&lt;/code&gt; &lt;code&gt;uchar first_char= (uchar)cur_struct;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(first_char==0){&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;register&lt;/code&gt; &lt;code&gt;int16 ires= (int16)(cur_struct&amp;gt;&amp;gt;16);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(ires==array_elements(symbols)) &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;register&lt;/code&gt; &lt;code&gt;SYMBOL *res= symbols+ires;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;register&lt;/code&gt; &lt;code&gt;uint count= (uint) (cur_str - s);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;lex_casecmp(cur_str,res-&amp;gt;name+count,len-count)!=0 ? 0 : res;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;register&lt;/code&gt; &lt;code&gt;uchar cur_char= (uchar)to_upper_lex[(uchar)*cur_str];&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(cur_char&amp;lt;first_char) &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;cur_struct&amp;gt;&amp;gt;=8;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(cur_char&amp;gt;(uchar)cur_struct) &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;cur_struct&amp;gt;&amp;gt;=8;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;cur_struct= uint4korr(hash_map+&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                        &lt;/code&gt;&lt;code&gt;(((uint16)cur_struct + cur_char - first_char)*4));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;cur_str++;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;其中的get_hash_symbol便是去系统中查找关键字，第三个参数function代表是否去查找系统函数，我们这里是系统变量，不是函数，故为FALSE。所有的关键字都挂在了hash_map上，即symbols_map上。symbols_maps又是一堆处理过的数据：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_667470&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;div&gt;4&lt;/div&gt;
&lt;div&gt;5&lt;/div&gt;
&lt;div&gt;6&lt;/div&gt;
&lt;div&gt;7&lt;/div&gt;
&lt;div&gt;8&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;static&lt;/code&gt; &lt;code&gt;uchar symbols_map[11828]= {&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;'&amp;lt;'&lt;/code&gt;&lt;code&gt;, &lt;/code&gt;&lt;code&gt;'&amp;gt;'&lt;/code&gt;&lt;code&gt;, 29, 0,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;'!'&lt;/code&gt;&lt;code&gt;, &lt;/code&gt;&lt;code&gt;'|'&lt;/code&gt;&lt;code&gt;, 32, 0,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;'&amp;lt;'&lt;/code&gt;&lt;code&gt;, &lt;/code&gt;&lt;code&gt;'X'&lt;/code&gt;&lt;code&gt;, 150, 0,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;'B'&lt;/code&gt;&lt;code&gt;, &lt;/code&gt;&lt;code&gt;'Y'&lt;/code&gt;&lt;code&gt;, 11, 1,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;'A'&lt;/code&gt;&lt;code&gt;, &lt;/code&gt;&lt;code&gt;'W'&lt;/code&gt;&lt;code&gt;, 147, 2,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;'A'&lt;/code&gt;&lt;code&gt;, &lt;/code&gt;&lt;code&gt;'V'&lt;/code&gt;&lt;code&gt;, 0, 4,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;...&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;看一下这个文件的最上面的注释吧，看看有啥有用的信息，果然被找到了：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_632445&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;/* Do not edit this file!  This is generated by gen_lex_hash.cc&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;that seeks for a perfect hash function */&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;看到了这个注释，心中豁然开朗，原来lex_hash.h是由gen_lex_hash.cc进行生成的，大家千万不要自己进行编辑此文件啊！！&lt;/p&gt;
&lt;p&gt;来gen_lex_hash.cc看下吧，看到了个main函数，里面是一些生成文件的操作，在generate_find_structs函数中找到了insert_symbols，&lt;/p&gt;
&lt;p&gt;这应该是初始化我们的symbols_map数组了吧。&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_994853&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;div&gt;4&lt;/div&gt;
&lt;div&gt;5&lt;/div&gt;
&lt;div&gt;6&lt;/div&gt;
&lt;div&gt;7&lt;/div&gt;
&lt;div&gt;8&lt;/div&gt;
&lt;div&gt;9&lt;/div&gt;
&lt;div&gt;10&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;void&lt;/code&gt; &lt;code&gt;insert_symbols()&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;size_t&lt;/code&gt; &lt;code&gt;i= 0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;SYMBOL *cur;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;for&lt;/code&gt; &lt;code&gt;(cur= symbols; i&amp;lt;array_elements(symbols); cur++, i++){&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;hash_lex_struct *root= &lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;get_hash_struct_by_len(&amp;amp;root_by_len,cur-&amp;gt;length,&amp;amp;max_len);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;insert_into_hash(root,cur-&amp;gt;name,0,(uint) i,0);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;看到函数的实现是循环取数组symbols,找到symbols定义，在文件lex.h中，看到这个数组，我想大家就会了然了:&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_208548&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;{ &lt;/code&gt;&lt;code&gt;&quot;SELECT&quot;&lt;/code&gt;&lt;code&gt;,     SYM(SELECT_SYM)},&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这就是将SELECT字符串与SELECT_SYM关联的地方了，bingo！&lt;/p&gt;
&lt;p&gt;我们再来捋一下SELECT解析的思路，词法分析解析到SELECT后，执行find_keyword去找是否是关键字，发现SELECT是关键字，&lt;/p&gt;
&lt;p&gt;于是给yacc返回SELECT_SYM用于语法分析。note：如果我们想要加关键字，只需在sql_yacc.yy上面添加一个%token xxx,&lt;/p&gt;
&lt;p&gt;然后在lex.h里面加入相应的字符串和SYM的对应即可。&lt;/p&gt;
&lt;p&gt;下面看下@@version_comment这个系统变量如何解析的，首先给出其语法节点：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_679580&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;div&gt;4&lt;/div&gt;
&lt;div&gt;5&lt;/div&gt;
&lt;div&gt;6&lt;/div&gt;
&lt;div&gt;7&lt;/div&gt;
&lt;div&gt;8&lt;/div&gt;
&lt;div&gt;9&lt;/div&gt;
&lt;div&gt;10&lt;/div&gt;
&lt;div&gt;11&lt;/div&gt;
&lt;div&gt;12&lt;/div&gt;
&lt;div&gt;13&lt;/div&gt;
&lt;div&gt;14&lt;/div&gt;
&lt;div&gt;15&lt;/div&gt;
&lt;div&gt;16&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;variable_aux:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;...&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;| &lt;/code&gt;&lt;code&gt;'@'&lt;/code&gt; &lt;code&gt;opt_var_ident_type ident_or_text opt_component&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;/* disallow &quot;SELECT @@global.global.variable&quot; */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;($3.str &amp;amp;&amp;amp; $4.str &amp;amp;&amp;amp; check_reserved_words(&amp;amp;$3))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;my_parse_error(ER(ER_SYNTAX_ERROR));&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(!($$= get_system_var(YYTHD, $2, $3, $4)))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(!((Item_func_get_system_var*) $$)-&amp;gt;is_written_to_binlog())&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;              &lt;/code&gt;&lt;code&gt;Lex-&amp;gt;set_stmt_unsafe();&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;          &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这里便是查找系统变量的地方了：get_system_var，我们跟进去看下：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_533199&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;div&gt;4&lt;/div&gt;
&lt;div&gt;5&lt;/div&gt;
&lt;div&gt;6&lt;/div&gt;
&lt;div&gt;7&lt;/div&gt;
&lt;div&gt;8&lt;/div&gt;
&lt;div&gt;9&lt;/div&gt;
&lt;div&gt;10&lt;/div&gt;
&lt;div&gt;11&lt;/div&gt;
&lt;div&gt;12&lt;/div&gt;
&lt;div&gt;13&lt;/div&gt;
&lt;div&gt;14&lt;/div&gt;
&lt;div&gt;15&lt;/div&gt;
&lt;div&gt;16&lt;/div&gt;
&lt;div&gt;17&lt;/div&gt;
&lt;div&gt;18&lt;/div&gt;
&lt;div&gt;19&lt;/div&gt;
&lt;div&gt;20&lt;/div&gt;
&lt;div&gt;21&lt;/div&gt;
&lt;div&gt;22&lt;/div&gt;
&lt;div&gt;23&lt;/div&gt;
&lt;div&gt;24&lt;/div&gt;
&lt;div&gt;25&lt;/div&gt;
&lt;div&gt;26&lt;/div&gt;
&lt;div&gt;27&lt;/div&gt;
&lt;div&gt;28&lt;/div&gt;
&lt;div&gt;29&lt;/div&gt;
&lt;div&gt;30&lt;/div&gt;
&lt;div&gt;31&lt;/div&gt;
&lt;div&gt;32&lt;/div&gt;
&lt;div&gt;33&lt;/div&gt;
&lt;div&gt;34&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;             &lt;/code&gt;&lt;code&gt;LEX_STRING component)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;sys_var *var;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;LEX_STRING *base_name, *component_name;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(component.str)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;base_name= &amp;amp;component;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;component_name= &amp;amp;name;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;else&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;base_name= &amp;amp;name;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;component_name= &amp;amp;component;         &lt;/code&gt;&lt;code&gt;// Empty string&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(!(var= find_sys_var(thd, base_name-&amp;gt;str, base_name-&amp;gt;length)))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(component.str)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;if&lt;/code&gt; &lt;code&gt;(!var-&amp;gt;is_struct())&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), base_name-&amp;gt;str);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;      &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;0;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;    &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;thd-&amp;gt;lex-&amp;gt;uncacheable(UNCACHEABLE_SIDEEFFECT);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;set_if_smaller(component_name-&amp;gt;length, MAX_SYS_VAR_LENGTH);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;  &lt;/code&gt;&lt;code&gt;return&lt;/code&gt; &lt;code&gt;new&lt;/code&gt; &lt;code&gt;Item_func_get_system_var(var, var_type, component_name,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                                      &lt;/code&gt;&lt;code&gt;NULL, 0);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;由find_sys_var函数不断跟进去，我们跟到了set_var.cc，找到了如下定义：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_572753&quot;&gt;
&lt;div&gt;&lt;a href=&quot;http://www.cnblogs.com/nocode/archive/2011/08/09/2132814.html#&quot;&gt;?&lt;/a&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;static&lt;/code&gt; &lt;code&gt;sys_var_chain vars = { NULL, NULL };&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;系统变量都会挂载在次链上。在文件中，搜索到了version_comment:&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_913095&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;static&lt;/code&gt; &lt;code&gt;sys_var_const_str    sys_version_comment(&amp;amp;vars, &lt;/code&gt;&lt;code&gt;&quot;version_comment&quot;&lt;/code&gt;&lt;code&gt;,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                                            &lt;/code&gt;&lt;code&gt;MYSQL_COMPILATION_COMMENT);&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_591320&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;#define MYSQL_COMPILATION_COMMENT   &quot;Source distribution&quot;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这便是将version_comment加载到vars的链表上。&lt;/p&gt;
&lt;p&gt;OK，我们也来加一个自己的系统变量：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_97256&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;div&gt;4&lt;/div&gt;
&lt;div&gt;5&lt;/div&gt;
&lt;div&gt;6&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;static&lt;/code&gt; &lt;code&gt;sys_var_const_str    sys_version_comment(&amp;amp;vars, &lt;/code&gt;&lt;code&gt;&quot;version_comment&quot;&lt;/code&gt;&lt;code&gt;,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                                            &lt;/code&gt;&lt;code&gt;MYSQL_COMPILATION_COMMENT);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;/**add by nocode */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;static&lt;/code&gt; &lt;code&gt;sys_var_const_str    sys_version_comment_test(&amp;amp;vars, &lt;/code&gt;&lt;code&gt;&quot;nocode_test_sysvar&quot;&lt;/code&gt;&lt;code&gt;,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                                            &lt;/code&gt;&lt;code&gt;MYSQL_COMPILATION_NOCODE_TEST_SYSVAR);&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;#define MYSQL_COMPILATION_COMMENT    “Source distribution”&lt;br /&gt;
#define MYSQL_COMPILATION_NOCODE_TEST_SYSVAR  “No code in heart”    /*add by nocode*/&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_522330&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt; &lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;注释add by nocode的地方，即是新添加的系统变量和宏定义，我们的系统变量叫@@nocode_test_sysvar,其值为No code in heartOK，重新编译代码，执行SELECT语句，OK了。&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_434984&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;div&gt;4&lt;/div&gt;
&lt;div&gt;5&lt;/div&gt;
&lt;div&gt;6&lt;/div&gt;
&lt;div&gt;7&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;mysql&amp;gt; &lt;/code&gt;&lt;code&gt;select&lt;/code&gt; &lt;code&gt;@@nocode_test_sysvar;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;+&lt;/code&gt;&lt;code&gt;----------------------+&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;| @@nocode_test_sysvar |&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;+&lt;/code&gt;&lt;code&gt;----------------------+&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;| &lt;/code&gt;&lt;code&gt;No&lt;/code&gt; &lt;code&gt;code &lt;/code&gt;&lt;code&gt;in&lt;/code&gt; &lt;code&gt;heart     |&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;+&lt;/code&gt;&lt;code&gt;----------------------+&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;1 row &lt;/code&gt;&lt;code&gt;in&lt;/code&gt; &lt;code&gt;set&lt;/code&gt; &lt;code&gt;(0.01 sec)&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;上面添加了一个系统变量，并没有修改语法文件sql_yacc.yy,为了加深理解，我们添加一个属于自己的语法：nocode语法，为了简单化实现，我们的目标很简单，在客户端输入no_code后显示字符串”MAKE BY NOCODE”。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定义关键字&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;首先在sql_yacc.yy文件中添加相应的SYMBOL&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_914162&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;%token  NO_SYM                        /* SQL-2003-R */&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;%token  NO_CODE_SYM                   /* &lt;/code&gt;&lt;code&gt;add&lt;/code&gt; &lt;code&gt;by&lt;/code&gt; &lt;code&gt;nocode*/&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;%token  NO_WAIT_SYM&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;然后在lex.h中的symblos数组中添加nocode的字符串和符号的对应关系：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_415614&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;{ &lt;/code&gt;&lt;code&gt;&quot;NO&quot;&lt;/code&gt;&lt;code&gt;,       SYM(NO_SYM)},&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{ &lt;/code&gt;&lt;code&gt;&quot;NO_CODE&quot;&lt;/code&gt;&lt;code&gt;,      SYM(NO_CODE_SYM)}, /*&lt;/code&gt;&lt;code&gt;add&lt;/code&gt; &lt;code&gt;by&lt;/code&gt; &lt;code&gt;nocode*/&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{ &lt;/code&gt;&lt;code&gt;&quot;NO_WAIT&quot;&lt;/code&gt;&lt;code&gt;,      SYM(NO_WAIT_SYM)},&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;ok,至此我们关键字已经添加进去了&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;添加语法节点&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们给语法分支节点起名叫nocode，定义如下：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_780738&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;div&gt;4&lt;/div&gt;
&lt;div&gt;5&lt;/div&gt;
&lt;div&gt;6&lt;/div&gt;
&lt;div&gt;7&lt;/div&gt;
&lt;div&gt;8&lt;/div&gt;
&lt;div&gt;9&lt;/div&gt;
&lt;div&gt;10&lt;/div&gt;
&lt;div&gt;11&lt;/div&gt;
&lt;div&gt;12&lt;/div&gt;
&lt;div&gt;13&lt;/div&gt;
&lt;div&gt;14&lt;/div&gt;
&lt;div&gt;15&lt;/div&gt;
&lt;div&gt;16&lt;/div&gt;
&lt;div&gt;17&lt;/div&gt;
&lt;div&gt;18&lt;/div&gt;
&lt;div&gt;19&lt;/div&gt;
&lt;div&gt;20&lt;/div&gt;
&lt;div&gt;21&lt;/div&gt;
&lt;div&gt;22&lt;/div&gt;
&lt;div&gt;23&lt;/div&gt;
&lt;div&gt;24&lt;/div&gt;
&lt;div&gt;25&lt;/div&gt;
&lt;div&gt;26&lt;/div&gt;
&lt;div&gt;27&lt;/div&gt;
&lt;div&gt;28&lt;/div&gt;
&lt;div&gt;29&lt;/div&gt;
&lt;div&gt;30&lt;/div&gt;
&lt;div&gt;31&lt;/div&gt;
&lt;div&gt;32&lt;/div&gt;
&lt;div&gt;33&lt;/div&gt;
&lt;div&gt;34&lt;/div&gt;
&lt;div&gt;35&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;/**&lt;/code&gt;&lt;code&gt;add&lt;/code&gt; &lt;code&gt;by&lt;/code&gt; &lt;code&gt;nocode*/&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;nocode:&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;NO_CODE_SYM&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;THD *thd= YYTHD;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;LEX *lex= Lex;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;SELECT_LEX *sel= lex-&amp;gt;current_select;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;Item_string* field;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;LEX_STRING tmp;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;CHARSET_INFO *cs_con= thd-&amp;gt;variables.collation_connection;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;CHARSET_INFO *cs_cli= thd-&amp;gt;variables.character_set_client;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if (sel-&amp;gt;linkage != UNION_TYPE)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;mysql_init_select(lex);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;lex-&amp;gt;current_select-&amp;gt;parsing_place= SELECT_LIST;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;uint repertoire= thd-&amp;gt;lex-&amp;gt;text_string_is_7bit &amp;amp;&amp;amp;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;my_charset_is_ascii_based(cs_cli) ? MY_REPERTOIRE_ASCII : MY_REPERTOIRE_UNICODE30;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;tmp.str = &lt;/code&gt;&lt;code&gt;&quot;MAKE BY NOCODE&quot;&lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;tmp.length = strlen(tmp.str);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;field= new (thd-&amp;gt;mem_root) Item_string(tmp.str, tmp.length, cs_con,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;DERIVATION_COERCIBLE,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;repertoire);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if (field== &lt;/code&gt;&lt;code&gt;NULL&lt;/code&gt;&lt;code&gt;)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;if (add_item_to_list(thd, field))&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;                &lt;/code&gt;&lt;code&gt;MYSQL_YYABORT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;Select&lt;/code&gt;&lt;code&gt;-&amp;gt;parsing_place= NO_MATTER;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;            &lt;/code&gt;&lt;code&gt;lex-&amp;gt;sql_command= SQLCOM_SELECT;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;        &lt;/code&gt;&lt;code&gt;;&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;最后要在statement的语法节点上加入nocode分支，我就不贴不来了。只要读到”no_code”便会进行进入这个语法分支。在这个分支里，做了一些操作，首先构造了一个SELECT类型的语句，然后对其添加了一列，这列的名称就是”MAKE BY NOCODE”…具体的细节大家自己研究吧，这都不是本文的重点。&lt;/p&gt;
&lt;p&gt;语法添加完之后，我们重新编译项目，值得说明的是，Mysql还是项目组织还是非常好的，修改了语法文件之后，不需要我们自己去用bison编译，项目自动就帮我们编译好了，真是不错。重启服务器，在客户端输入no_code,结果如下：&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_895491&quot;&gt;
&lt;div&gt;&lt;/div&gt;
&lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;div&gt;4&lt;/div&gt;
&lt;div&gt;5&lt;/div&gt;
&lt;div&gt;6&lt;/div&gt;
&lt;div&gt;7&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;code&gt;mysql&amp;gt; no_code;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;+&lt;/code&gt;&lt;code&gt;----------------+&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;| MAKE &lt;/code&gt;&lt;code&gt;BY&lt;/code&gt; &lt;code&gt;NOCODE |&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;+&lt;/code&gt;&lt;code&gt;----------------+&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;| MAKE &lt;/code&gt;&lt;code&gt;BY&lt;/code&gt; &lt;code&gt;NOCODE |&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;+&lt;/code&gt;&lt;code&gt;----------------+&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;1 row &lt;/code&gt;&lt;code&gt;in&lt;/code&gt; &lt;code&gt;set&lt;/code&gt; &lt;code&gt;(3.02 sec)&lt;/code&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;语法分析到此结束。这里只添加了一个很简单的语法分支，没啥用处，主要是介绍下添加分支的步骤，大家添加分支的时候要尽量使用已有的分支，既减少劳动量，同时也会减少语法冲突。 唠叨两句，最近项目太紧张，压力山大，每晚都被噩梦惊醒，噩梦中总会想到算法的各种BUG，写个代码都提心吊胆的，哎，搞IT的真是悲催啊。PS 终于又更新了一篇，oh yeah，-_-ps again: 第一次用windows live writer写博客，感觉比网页方便多了～～，赞一个&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3  class=&quot;related_post_title&quot;&gt;相关文章&lt;/h3&gt;&lt;ul class=&quot;related_post&quot;&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1107&quot; title=&quot;Mysql源码学习——没那么简单的Hash&quot;&gt;Mysql源码学习——没那么简单的Hash&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1105&quot; title=&quot;Mysql源码学习——用户认证原理与实现&quot;&gt;Mysql源码学习——用户认证原理与实现&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1102&quot; title=&quot;Mysql源码学习——Thread Manager&quot;&gt;Mysql源码学习——Thread Manager&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1100&quot; title=&quot;Mysql源码学习——Connection Manager&quot;&gt;Mysql源码学习——Connection Manager&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1098&quot; title=&quot;Mysql源码学习——八度空间&quot;&gt;Mysql源码学习——八度空间&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1095&quot; title=&quot;Mysql源码学习——源码目录结构&quot;&gt;Mysql源码学习——源码目录结构&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1090&quot; title=&quot;Mysql源码学习——词法分析MYSQLlex&quot;&gt;Mysql源码学习——词法分析MYSQLlex&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1088&quot; title=&quot;Mysql源码学习笔记——偷窥线程&quot;&gt;Mysql源码学习笔记——偷窥线程&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1086&quot; title=&quot;Mysql的源码安装&quot;&gt;Mysql的源码安装&lt;/a&gt;&lt;/li&gt;&lt;li&gt;2012-03-26 -- &lt;a href=&quot;http://ourmysql.com/archives/1084&quot; title=&quot;MySQL源码学习——DBUG调试&quot;&gt;MySQL源码学习——DBUG调试&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
	标签：&lt;a href=&quot;http://ourmysql.com/archives/category/advanced&quot; title=&quot;MySQL高级应用&quot; rel=&quot;tag&quot;&gt;MySQL高级应用&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/yacc&quot; title=&quot;YACC&quot; rel=&quot;tag&quot;&gt;YACC&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/%e6%ba%90%e7%a0%81&quot; title=&quot;源码&quot; rel=&quot;tag&quot;&gt;源码&lt;/a&gt;, &lt;a href=&quot;http://ourmysql.com/archives/tag/%e8%af%ad%e6%b3%95&quot; title=&quot;语法&quot; rel=&quot;tag&quot;&gt;语法&lt;/a&gt;&lt;br /&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/620768942/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1092&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://ourmysql.com/archives/1092/feed</wfw:commentRss><slash:comments>0</slash:comments><description>接触过SQL语句的人都会看过这家或者那家的SQL手册，其语法标准应该是从SQL92开始吧，在看SQL92标准的时候，你会发现里面定义的都是一些巴科斯范式(BNF)，就是一种语法定义的标准。不管是牛X哄哄的ORACLE，还是不幸被其收购的Mysql，都会遵循里面的标准语法，当然一些扩展的语法除外，比如今天我们就会扩展一个简单的语法^-^。&lt;img src=&quot;http://www1.feedsky.com/t1/620768942/ourmysql/feedsky/s.gif?r=http://ourmysql.com/archives/1092&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>源码</category><category>语法</category><category>MySQL高级应用</category><category>YACC</category><pubDate>Mon, 26 Mar 2012 13:32:50 +0800</pubDate><author>OurMySQL</author><comments>http://ourmysql.com/archives/1092#comments</comments><guid isPermaLink="false">http://ourmysql.com/?p=1092</guid><dc:creator>OurMySQL</dc:creator><fs:srclink>http://ourmysql.com/archives/1092</fs:srclink><fs:srcfeed>http://www.ourmysql.com/feed</fs:srcfeed><fs:itemid>feedsky/ourmysql/~7195843/620768942/5270018</fs:itemid></item></channel></rss>
