zoukankan      html  css  js  c++  java
  • 51ak带你看MYSQL5.7源码4:实现SQL黑名单功能

    博客迁移至:

    https://www.dboop.com/

    从事DBA工作多年

    MYSQL源码也是头一次接触

    尝试记录下自己看MYSQL5.7源码的历程

    申明:个人Python编程很溜,但是C++还停在白痴水平,源码理解方面有点弱,如发现有错误的地方,轻喷。

    博客的题目是看源码,实际上可能会发现在不停的在改源码,没办法,手贱,不改不舒服。

    目录:

    51ak带你看MYSQL5.7源码1:main入口函数 (2018-03-21)

    51ak带你看MYSQL5.7源码2:编译现有的代码 (2018-03-22)

    51ak带你看MYSQL5.7源码3:修改代码实现你的第一个Mysql版本 (2018-03-23)

    51ak带你看MYSQL5.7源码4:实现SQL黑名单功能(2018-04-11)

    上一篇我们实现了,屏掉了MYSQL的DELTE语句的执行功能。

    想了想这种改动太暴力了,不够优雅

    现在我们要改变一下思路,做一个MYSQL的黑名单功能。

    什么叫黑名单呢?

    就是说属于屏掉在带黑名单里的关键字的SQL的执行

    举例来说,

    我们发现有个上线故障,导致有大量的SQL在查一个表 SELECT * FROM A WHERE ...

    我们设置个黑名单: SELECT * FROM A  

    那么所有这种查询将不执行,直接返回,这对线上服务的快速缓解问题是有很大帮助的。


    现在我们来尝试在源码上定制这个功能

    首先按上一篇文章说的,找到sql_parse.cc 定位 到这个函数 void mysql_parse(THD *thd, Parser_state *parser_state

    通过 这一行

    DBUG_PRINT("mysql_parse", ("query: '%s'", thd->query().str));  可以看到执行的SQL文本,现在只需要判断这个文本是否包含指定的字符串就可以了。
    所以我们在入口的地方加上判断,如下:
     
    void mysql_parse(THD *thd, Parser_state *parser_state)
    {
      int error MY_ATTRIBUTE((unused));
      DBUG_ENTER("mysql_parse");
      DBUG_PRINT("mysql_parse", ("query: '%s'", thd->query().str));
      
      DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););
    
      #这里加我们的代码,目的是如果判断SQL文本中有指定字符abc ,直接退出。
      std::string  str_blacklist="abc";
      std::string  sqlstr_dba= thd->query().str;
      std::string::size_type idx_blacki = sqlstr_dba.find( str_blacklist );
    
      if ( idx_blacki != std::string::npos )
      {
         DBUG_PRINT("find blacklist sqlst",("query: '%s'", thd->query().str));
         return ;
      }
     #这里结束
      mysql_reset_thd_for_next_command(thd);
      lex_start(thd);

    编译安装,随便 执行个SQL发现没问题,只要带上abc这个字符,立即退出,黑名单功能实现

    但是我们不可能每次修改SQL黑名单都要修改一次MSYQL源码,这不现实,所以需要把这个黑名单做成系统变量 variables

    这里注意了,一共是两个地方需要修改,全局变量定义放在mysqd.cc中 而变量的值初始化在sys_vars.cc中

    打开mysqd.cc 加上

    char *opt_black_sqlstr;
    opt_black_sqlstr= NULL;
    在mysqld.h里面加上:
    extern char *opt_black_sqlstr;
     
    以下完成了变量的申明
    然后打开sys_vars.cc,加上下面这行初始化代码。
    static Sys_var_charptr Sys_black_sqlstr(
           "black_sqlstr",
           "the black list sqlstr --by 51ak ",
           READ_ONLY GLOBAL_VAR(opt_black_sqlstr), CMD_LINE(REQUIRED_ARG),
           IN_FS_CHARSET, DEFAULT(0));

    现在我们完成了增加一个系统变量,也完成了SQL黑名单的判断,把这两个结合起来。执行SQL时如果文本中包含black_sqlstr中的文本,则强行退出执行。

    我们去修改mysql_parse.cc

      std::string  str_blacklist=opt_black_sqlstr;
      std::string  sqlstr_dba= thd->query().str;
      std::string::size_type idx_blacki = sqlstr_dba.find( str_blacklist );
    
      if ( idx_blacki != std::string::npos )
      {
         DBUG_PRINT("find blacklist sqlst",("query: '%s'", thd->query().str));
         return ;
      }

    接下来编译,安装

    修改配置文件 ,默认是/etc/my.cnf

    增加一个变量black_sqlstr=order

    进入MYSQL,试一下:

    #查一下我们设置的变量
    mysql> show global variables like '%black%';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | black_sqlstr  | order |
    +---------------+-------+
    1 row in set (0.02 sec)
    

    #尝试触发黑名单 mysql
    > select 'order'; ERROR 2013 (HY000): Lost connection to MySQL server during query



    #尝试触发黑名单
    mysql> select * from dba_test.op_log where content like '%order%';
    ERROR 2013 (HY000): Lost connection to MySQL server during query
    mysql
    >

    好,一个SQL黑名单功能 已经完成,

    通过这个例子,做了两个层面的修改,定义一个Mysql变量,使用这个变量来完成SQL限定的功能。

    大家举一反三,发现更多的利用方式 

    今天到此为止。

     
  • 相关阅读:
    性能测试理论知识
    接口测试笔试题
    测试计划与测试报告
    java基础面试题
    软件测试人员必备的linux命令
    tomcat各目录(文件)作用
    常见的面试题
    LoadRunner中怎么设置密码参数化与用户名关联
    数据库索引总结(二)
    数据库索引总结(一)
  • 原文地址:https://www.cnblogs.com/wokofo/p/8632790.html
Copyright © 2011-2022 走看看