sql的代码可以在mysql_如何在修改mysql代码添加新SQL命令

本文主要介绍如何在mysql中添加一条新SQL命令, 例如 DISPATCH ADD "gao", 这条命令会去检查参数的值是否为“gao”, 如果是的话 就把全局变量node_type设为1 (默认为0).

注:关于全局变量node_type 请查看我的另一篇文章<> : http://hi.baidu.com/gao1738/blog/item/84ff8cde9f8f221f92457ec6.html .

说明: 这里要添加的命令本身没太大意义,主要就是介绍一下mysql的命令解析机制和如何添加命令。

关于mysql如何解析命令可以先阅读下这个链接: http://wenku.baidu.ocom/view/3bb97a1dc5da50e2524d7ff7.html 。

1. 概述

mysql主要是用 lex+yacc 的方式进行命令构建与分析的

我们首先要做的就是在lex和yacc的代码文件中添加新命令的 字符定义与语法定义

然后我们要让mysql认识我们的新命令

最后添加与新命令对应的处理代码

命令解析大体上的流程是:

【1.判断命令类型】->【2.根据类型对命令进行分发,分发到对应解析程序】->【3.对命令解析】->【4.根据具体的命令进行分发,分发到对应的命令处理程序】->【5. 处理命令】

第一步对应的代码在 sql/sql_parse.cc的do_command中。 (目前只碰到过COM_QUERY的类型,还不清楚命令的类型在哪里的决定的,以后补充。)补:所有从客户端发送的sql语句都是COM_QUERY类型的,这个写死在代码里面了,具体的代码在sql-common/client.c中的mysql_send_query函数中。

第二步对应的代码在同一个文件的dispatch_command中。

第三步对应的代码在同文件的sql_parse中。

第四步对应的代码在同文件的mysql_execute_command中。

最后一步对应的代码就不一定了,看具体的命令而定。

2. 在lex和yacc的代码文件中添加新命令的 字符定义与语法定义

修改的文件:

sql/lex.h

sql/sql_yacc.yy

在sql_yacc.yy中添加 新的字符定义 (大约1400行)找到一列的%token定义的地方,在那里添加如下定义:

%token DISPATCH

然后(大约1640行)找到 %type 在最后添加上DISPATCH, 如下: %type

'-' '+' '*' '/' '%' '(' ')'sql_yacc.h

',' '!' '{' '}' '&' '|' AND_SYM OR_SYM OR_OR_SYM BETWEEN_SYM CASE_SYM

THEN_SYM WHEN_SYM DIV_SYM MOD_SYM OR2_SYM AND_AND_SYM DELETE_SYM

DISPATCH

在lex.h在中找到 "static SYMBOL symbols[]"在它的末尾(大约624行)添加如下代码:

{ "DISPATCH", SYM(DISPATCH)}

注:

(

在sql/sql_yacc.yy中 通过“%union” 定义了在语法解析过程中 用户输入语句块的可选类型。 例如“int num”表示所有num类型的参数都是整形。 字符型的大都返回的都是LEX_STRING类型, 这个类型在include/m_string.h中定义。

用户可以自己定义类型, 下面是一个例子:

1. 在%union中添加 新类型:

Exec_node *e_node;

2. 定义使用这个类型的语句块:

%type name_ip_port

3. 解析语句时使用这个类型:

+dispatch_param:

+ ADD NODE_SYM name_ip_port

+ {

+ LEX *lex= Lex;

+ lex->sql_command= SQLCOM_ADD_DISPATCH_NODES;

+ Lex->execution_node= $3; //这里$3指的是 name_ip_port 这个语句块

+ };

4. 在解析类型对应语句块时创建类型对象:

+name_ip_port:

+ TEXT_STRING_sys TEXT_STRING_sys TEXT_STRING_sys

+ {

+ THD *thd= YYTHD;

+ if (!($$= (Exec_node*)thd->alloc(sizeof(Exec_node)))) //alloc是mysql提供的函数,用于在lex中分配空间

+ MYSQL_YYABORT;

+

+ strcpy($$->name, $1.str);

+ strcpy($$->address, $2.str); //$$表示这个语句块要返回的对象

+ $$->port= atoi($3.str);

+ }

+ ;

)

在sql_yacc.h中找到"enum yytokentype" 在它的末尾添加上dispatch: (这个文件似乎是根据sql/sql_yacc.yy自动生成的,无需自己手动添加)

DISPATCH = 854

和对应的#define DISPATCH 854

(以上忽略)

修改文件:sql/sql_yacc.yy

在sql_yacc.yy中找到 语法定义 “statement:" (大约1723行) (它是语法query的一部分)

在其中添加上 一个语法分支“dispatch”, 例如:

statement:

...... | truncate

| uninstall

| unlock

| update

| use

| xa

| dispatch

;

然后在其后添加 dispatch的具体语法:(这里除了定义了DISPATCH ADD 还定义了 DISPATCH DELETE, 但后面的例子只用到DISPATCH ADD)

dispatch:

DISPATCH add_delete;

add_delete:

dispatch_add|dispatch_delete;

dispatch_add:

ADD ident // ident在其他地方定义了, 主要用来表示 字符(例如用于名字的)

{

THD *thd= YYTHD;

LEX *lex= thd->lex;

lex->sql_command= SQLCOM_DISPATCH_ADD; //这里设置了命令标识, 这个标识的定义在下一步中会介绍

char *tmp=(char*) thd->alloc(sizeof(char)); //这里需要为变量字符在lex的存储空间中分配一个空间来存变量值

strcpy(tmp, $2.str); // $2表示命令的第2个部分,这里是指"ADD indent"中的indent

lex->dispatch_message=tmp; //lex->dispatch_message是在lex结构中新定义的,后面会介绍

};

dispatch_delete:

DELETE_SYM ident

{

THD *thd= YYTHD;

LEX *lex= thd->lex;

lex->sql_command= SQLCOM_DISPATCH_DELETE;

lex->dispatch_message= $2.str;

}

;

注: 这里需要注意避免定义的语法有2义性, 这会导致一个编译错误:“sql/sql_yacc.yy:expected 164 shift/reduce conflicts”

3. 让mysql认识我们的新命令

修改文件:sql/sql_cmd.h

sql/mysqld.cc

sql_cmd.h找到"enum enum_sql_command"(大约88行)中添加如下代码:

SQLCOM_DISPATCH_ADD, SQLCOM_DISPATCH_DELETE

这就是2个新命令的标识。它们在上一步的语法定义中被使用。

然后在mysqld.cc中大约3093行找到 "SHOW_VAR com_status_vars[]"在它的最后一项前添加如下代码:

{"dispatch_add", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DISPATCH_ADD]),SHOW_LONG_STATUS},

{"dispatch_delete", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DISPATCH_DELETE]),SHOW_LONG_STATUS},{NullS, NullS, SHOW_LONG}

};

注:以上在mysqld.cc中的修改主要是为了能通过mysql非常严格的编译脚本,否则无法通过mysqld.cc中大约3259行的断言compile_time_assert,关于其中的意义现在还不是很了解,以后补充。

3.添加与新命令对应的处理代码

修改文件: sql/sql_lex.h

在sql_lex.h中找到“struct LEX”的定义(大约2054行)然后在其中添加如下代码: char* x509_subject,*x509_issuer,*ssl_cipher;

String *wild;

char *dispatch_message;

sql_exchange *exchange;

select_result *result;

这里定义的“dispatch_message” 就是用来存储命令的参数值的。该变量在第一步中的语法定义中被使用。

修改文件:sql/sql_parse.cc, 可能还有其他的,看具体需求

在sql_parse.cc中找到 “mysql_execute_command” 函数, 在其中有个很大的swith. 在这个swith中添加我们新命令对应的case:

case SQLCOM_DISPATCH_ADD:

case SQLCOM_DISPATCH_DELETE:

{

if (!strcmp(lex->dispatch_message, "gao"))

{

global_system_variables.node_type=1;

my_ok(thd); //这句代码设置查询的返回状态为ok 这很重要,否则无法通过mysql在

//查询对应的状态由thd->stmt_da->status()查看

//该值将会在sql/Protocol的end_statement中进行判断处理,如果为空的话

//将导致DBUG_ASSERT(0);

//注:这里如果要添加验证并做对应的错误处理,可以使用如下语句:

// my_error(ER_WRONG_ARGUMENTS, MYF(0), "something you want to say in the error");

//“ER_WRONG_ARGUMENTS” 这个是错误类型, 在include/mysqld_error.h中定义的。 这个错误类型可以在测试用例中用--error捕捉,例如:

//--error ER_WRONG_ARGUMENTS

//DISPATCH ADD node_test;

//如果测试用例在执行“DISPATCH ADD node_test;” 时产生“ER_WRONG_ARGUMENTS ” 错误的话, 这个错误会被捕捉,并将预定义的

//错误信息打印。 使用这种方式可以在测试用例中添加错误测试,并设置预期要捕捉的错误

//“MYF(0)” 是把0转成int类型, 这个宏在include/my_global.h中定义, 这个值如果设置成1 的话,mysql会向标准错误输出中输入/007, 即

//一个错误提示音。 相关的代码处理在mysys/my_mess.c的24行,函数my_message_stderr中。

}

else

my_eof(thd);

break;

}

4. 对应的测试用例

在mysql-test/t 下面建立一个测试用例文件gao.test, 内容如下:

DISPATCH ADD gao;

show variables like 'node_type';

然后在mysql-test/目录下执行

./mtr gao

结果如下:

==============================================================================

TEST RESULT TIME (ms) or COMMENT

--------------------------------------------------------------------------

worker[1] Using MTR_BUILD_THREAD 300, with reserved ports 13000..13009

DISPATCH ADD gao;

show variables like 'node_type';

Variable_name Value

node_type 1

main.gao [ pass ] 3

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值