• MySQL源码学习——USE语句的秘密



    MySQL源码学习——USE语句的秘密

    Louis Hust

     

    0  Preface

    最近一个项目需要解析MySQL的通信协议,这时候便碰到了USE语句的解析,发现客户端 mysql发送到服务器端的USE语句对应的并不是SQLCOM_CHANGE_DB命令,而是COM_INIT_DB。 而且这两个命令的处理逻辑基本一致,都是调用mysql_change_db进行处理,那么什么时候 发送COM_INIT_DB,什么时候发送SQLCOM_CHANGE_DB命令呢?这便是本文需要解释的地方。

     

    0  COM_INIT_DB 与 SQLCOM_CHANGE_DB

    首先解释下这两个命令,其实这两个命令不是在一个层次的,COM_INIT_DB命令是最高层次的命令, SQLCOM_CHANGE_DB属于COM_QUERY中的一个子命令,属于一个低层次的命令。那么何为高层次的命令, 什么又是低层次的命令么?

     

    客户端发过来的命令均是高层次的命令,即均是COM开头的命令,区别不同的高层次命令是由数据包中的第 4个字节(包含第0字节)进行确定(即跳过packet header四个字节后的第一个字节)。COM_INIT_DB在 第4个字节上使用0x02,COM_QUERY使用0x03.

     

    SQLCOM_CHANGE_DB命令属于COM_QUERY的一个子命令,客户端发送过来的只是一个QUERY,并不知道这个 QUERY是要CHANGE DB还是要做SELECT或者其他操作,这就需要服务器端进行语法解析,即所谓的YACC语法解析。 经过解析后才能知道这条命令到底是什么,这就是低层次的命令。只有COM_QUERY这类高层命令需要解析出低层 命令。

     

    0  什么时候发送COM_INIT_DB?

    其实直接使用mysql客户端执行use语句的时候,你会发现,服务器端执行的是COM_INIT_DB命令, 而不是直接是COM_QUERY,这说明客户端一定对语句做了一些处理,如果不处理的话,所有输入客户端的 命令,mysql应该都认为是COM_QUERY,而事实并非如此。

     

    那我们跟踪一下代码就会发现,确实mysql客户端进行了一些预处理工作。下面先给出一个客户端 USE语句的跟踪堆栈。

    mysql> use mysql
    (gdb) bt
    #0  com_use (buffer=0x93c0c0 <glob_buffer>, line=0x9f5570 "use mysql") at /home/loushuai/src/mysql/hust-mysql/client/mysql.cc:4118
    #1  0x000000000040c619 in read_and_execute (interactive=true) at /home/loushuai/src/mysql/hust-mysql/client/mysql.cc:1932
    #2  0x000000000040b657 in main (argc=8, argv=0x948418) at /home/loushuai/src/mysql/hust-mysql/client/mysql.cc:1230
    
    

    从堆栈可以看出,这里调用了com_use函数专门处理USE语句。下面给出调用的伪代码。

    main
    {
      ...
      read_and_exeucte()
      ...
    }
    
    read_and_execute
    {
    
      ...
      for (;;)
      {
      ...
      /**读取命令 */
          line= readline(prompt);
    
          ...
        if ((named_cmds || glob_buffer.is_empty())
      && !ml_comment && !in_string && (com=find_command(line,0)))
        {
          /** 如果find到command, 则执行相应的func */
          if ((*com->func)(&glob_buffer,line) > 0)
            break;
    
        }
    
      }
      ...
    }
    
    find_command函数即在预定义的commands数组中查找相应的命令。
    
    static COMMANDS commands[] = {
      { "?",      '?', com_help,   1, "Synonym for `help'." },
      { "clear",  'c', com_clear,  0, "Clear the current input statement."},
      { "connect",'r', com_connect,1,
        "Reconnect to the server. Optional arguments are db and host." },
      { "delimiter", 'd', com_delimiter,    1,
        "Set statement delimiter." },
    #ifdef USE_POPEN
      { "edit",   'e', com_edit,   0, "Edit command with $EDITOR."},
    #endif
      { "ego",    'G', com_ego,    0,
        "Send command to mysql server, display result vertically."},
      { "exit",   'q', com_quit,   0, "Exit mysql. Same as quit."},
      { "go",     'g', com_go,     0, "Send command to mysql server." },
      { "help",   'h', com_help,   1, "Display this help." },
    #ifdef USE_POPEN
      { "nopager",'n', com_nopager,0, "Disable pager, print to stdout." },
    #endif
    
    
     

    0  什么时候发送SQLCOM_CHANGE_DB?

    这个命令的发送比较简单,只要不通过mysql客户端即可。可以通过一些Connector以Query的方式 进行执行,如C API提供的mysql_query函数,mysql_query(conn, üse test");

     

    顺便说一下,mysql test框架中的测试用例的解析(调用mysqltest进行解析), 是直接使用的C的API进行处理的,所以不会 出现mysql客户端中预处理的情况。即USE TEST会被解析未SQLCOM_CHANGE_DB命令。

     




    File translated from TEX by TTH, version 4.03.
    On 30 Apr 2013, 19:42.

    踏着落叶,追寻着我的梦想。转载请注明出处
  • 相关阅读:
    Android 百度地图 SDK v3.0.0 (三) 添加覆盖物Marker与InfoWindow的使用
    玩转Web之html+CSS(一)---论坛首页表格的实现
    Android 百度地图 SDK v3.0.0 (二) 定位与结合方向传感器
    Android 百度地图 SDK v3.0.0 (一)
    RabbitMQ (五)主题(Topic)
    RabbitMQ (四) 路由选择 (Routing)
    数据结构中的排序算法
    冒泡排序
    hashMap与hashTable的区别
    Java重载与重写的区别
  • 原文地址:https://www.cnblogs.com/nocode/p/3052337.html
Copyright © 2020-2023  润新知