探索MYSQL源代码–添加一个函数

我们来为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

 

觉得文章有用?立即: 和朋友一起 共学习 共进步!

猜您喜欢

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>