我们来为MySQL添加一个函数,名为show disk_usage
mysql> show disk_usage; +----------+-----------+ | Database | Size (Kb) | +----------+-----------+ | test_row | 120400 | +----------+-----------+ 1 row in set (0.00 sec)
要修改新的函数,涉及到词法分析,我们先来修改sql/lex.h文件。
找到static SYMBOL symbols[] 这个结构体,添加一个”DISK_USAGE”这个词法,效果如下
{ "DISK", SYM(DISK_SYM)}, /*start*/ { "DISK_USAGE", SYM(DISK_USAGE_SYM)}, /*end */ { "DISTINCT", SYM(DISTINCT)}
于是词法分析的时候会DISK_USAGE这个词法当做一个token转化为内部枚举DISK_USAGE_SYM。
有新的词法,我们为新词法添加新语法,我们来修改sql/yacc.yy文件。
来到token区域,添加一个token,名字于lex.h一样,这样语法分析器bison才能知晓词法分析器flex传过来的token对应的枚举。
%token DISK_SYM /*start*/ %token DISK_USAGE_SYM /*end*/ %token DISTINCT
继续添加发现show disk_usage()语法匹配之后的行为
搜索关键字show: 添加新的行为
show: /*start*/ SHOW DISK_USAGE_SYM { LEX *lex = Lex; sql_command = SQLCOM_SHOW_DISK_USAGE; } | /*end*/ SHOW
到这里为止词法语法部分添加完毕。
SQLCOM_SHOW_DISK_USAGE产生什么效果呢,需要指向具体的函数。
在添加具体函数之前,还需要让SQLCOM_SHOW_DISK_USAGE成为一个合法的sql_command,我们需要修改sql/sql_lex.h。找到关键字enum enum_sql_command, 把SQLCOM_SHOW_DISK_USAGE作为一个enum添加进去
SQLCOM_SHOW_PROFILE, SQLCOM_SHOW_PROFILES, /*start*/ SQLCOM_SHOW_DISK_USAGE, /*end*/ /* When a command is added here, be sure it's also added in mysqld.cc in "struct show_var_st status_vars[]= {" ... */ /* This should be the last !!! */ SQLCOM_END };
接着还要在sql/mysqld.cc 里再添加一遍, 找到关键字SHOW_VAR com_status_vars[]= {
{"show_authors", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_AUTHORS]), SHOW_LONG_STATUS}, /*start*/ {"show_disk_usage", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_DISK_USAGE]), SHOW_LONG_STATUS}, /*end*/ {"show_binlog_events", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOG_EVENTS]), SHOW_LONG_STATUS},
不添加这部会出现编译时的ASSERT错误。
接着把SQLCOM_DISK_USAGE指向具体函数, 修改sql/sql_parse.cc,关键字mysql_execute_command
switch (lex->sql_command) { /*start*/ case SQLCOM_SHOW_DISK_USAGE: res = show_disk_usage_command(thd); break; /*end*/ case SQLCOM_SHOW_EVENTS:
好了终于指向了具体的函数show_disk_usage_command(),我们接着来实现这个函数。
在sql/mysql_priv.h添加一个申明
bool mysqld_help (THD *thd, const char *text); /*start*/ bool show_disk_usage_command(THD *thd); /* end */ void calc_sum_of_all_status(STATUS_VAR *to);
在sql/sql_show.cc添加一个具体的实现
bool show_disk_usage_command(THD *thd) { DBUG_ENTER("show_disk_usage"); List field_list; List dbs; Protocol *protocol = thd->protocol; /*set fields*/ field_list.push_back(new Item_empty_string("Database", 50)); field_list.push_back(new Item_empty_string("Size (Kb)", 30)); if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS|Protocol::SEND_EOF)) DBUG_RETURN(TRUE); /*set data*/ protocol->prepare_for_resend(); protocol->store("test_row", system_charset_info); protocol->store("1024000", system_charset_info); if (protocol->write()) DBUG_RETURN(TRUE); my_eof(thd); DBUG_RETURN(FALSE); } /*end*/ bool mysqld_show_authors(THD *thd)
make clean; make;make install
好了,效果就可以看到了
mysql> show disk_usage; +----------+-----------+ | Database | Size (Kb) | +----------+-----------+ | test_row | 1024 | +----------+-----------+ 1 row in set (0.00 sec)
ps : 部分参考expert mysql
for douban: doubanclaimfdd64e647e42d240