本文主要介绍如何在mysql 中添加新的源文件以及如何在客户端打印列表信息。 这两个内容没有必然的联系,这里放在一起介绍主要是因为这两个功能我是一起尝试的。
1. 添加新源文件
mysql5.5的编译是基于cmake来进行的, 所以当添加新的源文件的时候,需要在对应源码目录的cmake配置文件CMakeList.txt中添加新源文件的信息。
本例中添加的新文件是gaoshow.h 和gaoshow.cc, 它们都在sql源码目录下。
编辑sql源码目录下的CMakeList.txt,大约第39行处找到变量定义 “SET(SQL_SHARED_SOURCES” 在其后的列表的末尾添加gaoshow.cc (cmake中只需要添加.cc文件,不需要添加.h头文件)。
2. 添加“客户端打印列表信息”的功能
这个功能基于之前的博文 《如何在修改mysql代码添加新命令》:http://hi.baidu.com/gao1738/blog/item/716e1aeb3e0a5a0b6c22eb46.html。
在《如何在修改mysql代码添加新命令》中我添加了一条新的命令"DISPATCH ADD", 现在在该命令的命令处理代码处:
sql_parse.cc中的 “mysql_execute_command”函数中的“case SQLCOM_DISPATCH_ADD:”。具体修改后的处理代码如下:
if (!strcmp(lex->dispatch_message, "gao"))
{
global_system_variables.node_type=1;
show_dispatch_info(thd,lex->dispatch_message);
//my_ok(thd);
my_eof(thd); //注:这里一定要用my_eof(thd)来结束, 而不能用my_ok(thd),否则执行该命令的过程中
// mysql会卡死在哪
// 但如果这条命令没有向客户端发送数据的话 就用 my_ok(thd)
// 客户端总是期待服务端发送的数据集以 "eof" 或 “error packet” 结尾。
}
“show_dispatch_info” 函数定义在新填的源文件中:
这个头文件需要在sql_parse.cc中被include
3.
#ifndef GAO_SHOW
#define GAO_SHOW
bool show_dispatch_info(THD *thd, char *message);
#endif
#include "sql_parse.h"
#include "gaoshow.h"
#include <my_dir.h>
bool show_dispatch_info(THD *thd, char *message)
{
Protocol *protocol= thd->protocol;
DBUG_ENTER("show_dispatch_info");
field_list.push_back(new Item_empty_string("message", 255)); //注:这里是设置表头
//注:这里是设置表头
if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
protocol->prepare_for_resend();
protocol->store(message,&my_charset_bin);
//注:这里是设置表头对应的值, 按顺序一一对应
protocol->store((ulonglong)10);
//注:这里是设置表头对应的值, 按顺序一一对应
if (protocol->write())
DBUG_RETURN(TRUE);
else
DBUG_RETURN(FALSE);
}
这里我们直接使用《如何在修改mysql代码添加新命令》中定义的测试用例, 执行结果如下:
==============================================================================
TEST
RESULT
TIME (ms) or COMMENT
--------------------------------------------------------------------------
worker[1] Using MTR_BUILD_THREAD 300, with reserved ports 13000..13009
DISPATCH ADD gao;
message
num
gao
10
show variables like 'node_type';
Variable_name
Value
node_type
1
main.gao
[ pass ]
1
4. 打印多行数据
打印多行的过程和打印一行很类似, 也是通过protocol对象, 也是先设置并发送数据的metadata, 然后一行一行发送,发送具体一行的代码可以参考sql/sql_class.cc中1895行的send_data函数。 下面是一个简单的实例:
bool show_dispatch_info(THD *thd, const char *message)
{
Protocol *protocol= thd->protocol;
DBUG_ENTER("show_dispatch_info");
List<Item> field_list;
//用这个list存放metadata
field_list.push_back(new Item_empty_string("message", 255));
//这里是设置metadata
field_list.push_back(new Item_return_int("Position",20,MYSQL_TYPE_LONGLONG));
//这里是设置metadata
if (protocol->send_result_set_metadata(&field_list,
//向客户端发送要显示的metadata
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
List<Item> items; //这个list用来存放每一行的数据
items.push_back(new Item_string(message, strlen(message), system_charset_info)); //放第一个数据项
//注这里的message中的值 如果你不是在这个命令使用,而是要保存到以后的命令中使用,
//那么需要把它深拷贝到 另一块new的内存中。 因为lex中的对象在这条语句结束后就释放了。
items.push_back(new Item_int(10));
//放第二个数据项
send_row_data(items, protocol, thd);
items.delete_elements();
items.push_back(new Item_string("end", strlen("end"), system_charset_info));
items.push_back(new Item_int(0));
send_row_data(items, protocol, thd);
items.delete_elements();
items.push_back(new Item_string("end", strlen("end"), system_charset_info));
items.push_back(new Item_int(0));
send_row_data(items, protocol, thd);
DBUG_RETURN(TRUE);
}
bool send_row_data(List<Item> l, Protocol *p, THD *thd)
{
DBUG_ENTER("show_row_data"); //对于每个函数这个必须放在第一行, 它告诉debuger进入了一个新的用户函数,并且在栈中
p->prepare_for_resend();
//准备发送数据
if (p->send_result_set_row(&l))
//设置要送发的数据
{
p->remove_last_row();
DBUG_RETURN(TRUE);
}
thd->sent_row_count++;
if (p->write())
DBUG_RETURN(TRUE);
else
DBUG_RETURN(FALSE);
}
5. 多行数据的测试
DISPATCH ADD gao;
//这个是执行的命令
message
Position
gao
10
end
0
end
0
DISPATCH ADD xiao;
//这个是执行的命令
message
Position
delete
10
end
0
end
0