mysql源码探究之mysql client

mysql命令行客户端源码位于client目录下,main函数位于mysql.cc文件里。
main函数里首先进行一些初始化工作,包括读取配置参数、申请内存、初始化变量等,然后会调用read_and_execute函数,这个函数内部会做read-eval循环。
read_and_execute函数在每次循环内,先调用readline读取用户输入,然后调用find_command来处理命令。 find_command函数里会拿用户输入在commands这个全局变量里查找。commands变量是COMMANDS结构体数组,里面定义了mysql支持的命令。 命令结构定义如下:

typedef struct
{
  const char *name;                 /* User printable name of the function. */
  char cmd_char;                    /* msql command character */
  int (*func)(String *str, char *); /* Function to call to do the job. */
  bool takes_params;                /* Max parameters for command */
  const char *doc;                  /* Documentation for this function.  */
} COMMANDS;

commands数组里只有参数类命令才定义了func成员变量,而查找修改数据类命令的func成员都是0,由此可以推测出这些命令都是在服务端进行实际操作的。 所以对于select * from table这条语句,find_command函数无法找到合适的命令来处理,会继续调用add_line函数,内部会调用com_go函数。 com_go会调用mysql_real_query_for_lazy函数,经过多层调用,最后会调用simple_command函数,并传递COM_QUERY参数。 mysql支持的参数如下:

enum enum_server_command
{
  COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST,
  COM_CREATE_DB, COM_DROP_DB, COM_REFRESH, COM_SHUTDOWN, COM_STATISTICS,
  COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING,
  COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP,
  COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE,
  COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_SEND_LONG_DATA, COM_STMT_CLOSE,
  COM_STMT_RESET, COM_SET_OPTION, COM_STMT_FETCH, COM_DAEMON,
  /* don't forget to update const char *command_name[] in sql_parse.cc */

  /* Must be last */
  COM_END
};

而simple_command函数只是一层包装,实际调用MYSQL结构体的methods成员变量的advanced_command成员函数。而这个成员函数是初始化时在mysql_real_connect函数里赋值的,实际值定义如下:

MYSQL_METHODS embedded_methods= 
{
  emb_read_query_result,
  emb_advanced_command,
  emb_read_rows,
  emb_store_result,
  emb_fetch_lengths, 
  emb_flush_use_result,
  emb_read_change_user_result,
  emb_list_fields,
  emb_read_prepare_result,
  emb_stmt_execute,
  emb_read_binary_rows,
  emb_unbuffered_fetch,
  emb_free_embedded_thd,
  emb_read_statistics,
  emb_read_query_result,
  emb_read_rows_from_cursor
};

所以会调用emb_advanced_command函数,内部会调用dispatch_command函数。 之后调用mysql_store_result_for_lazy函数来读取结果,类似的,会调用mysql->methods->read_rows,即emb_read_rows函数。