|
一、户端客户端显示字符背景介绍 MySQL最新版本有一个新功能,显示在使用客户端的字符时候,最后加上--skip-binary-as-hex选项可以直接显示二进制值对应的代码字符串,不加该选项就可以按照原来的改造设置格式显示。先来看一下以下的户端varbaniry的显示例子。 #建表: 
create table varb(id int,显示bb varbinary(1000)); insert into varb values(1,abcd); #登录: mysql -h 127.0.0.1 -P3307 -uroot --skip-binary-as-hex mysql> select * from varb; +------+------+ | id | bb | +------+------+ | 1 | abcd | +------+------+ 1 row in set (0.00 sec)如果不加--skip-binary-as-hex选项的显示如下: mysql -h 127.0.0.1 -P3307 -uroot mysql> select * from varb; +------+------------+ | id | bb | +------+------------+ | 1 | 0x61626364 | +------+------------+ 1 row in set (0.01 sec)这个功能对于用惯了旧版本的同学们有的会觉得不方便,今天这里动手改造一下都显示成字符格式而不用通过--skip-binary-as-hex选项设置。字符 二、代码代码跟踪沿用上面的改造表查询一下哪段代码决定字符的云服务器显示格式,代码解析如下: 输入该命令后找到相关字符显示的户端代码: mysql> select * from varb;class Item_field的成员函数如下: const CHARSET_INFO *charset_for_protocol(void) override { return field->charset_for_protocol(); #表字段的字符显示取决于field的字符设置。 }继续找到class Field的显示成员函数如下: const CHARSET_INFO *charset_for_protocol() const { return binary() ? &my_charset_bin : charset(); #field的字符设置取决于是否binary类型。 }输入以上命令GDB跟踪一下代码堆栈: Thread 47 "mysqld" hit Breakpoint 3,字符 Item_field::charset_for_protocol (this=0x7fff340bc1f0) at /home/greatdb/sql/item.h:4373 4373 const CHARSET_INFO *charset_for_protocol(void) override { (gdb) bt #0 Item_field::charset_for_protocol (this=0x7fff340bc1f0) at /home/greatdb/sql/item.h:4373#1 0x0000555558e60ca8 in THD::send_result_metadata (this=0x7fff34000c00, list=..., flags=5) at /home/greatdb/sql/sql_class.cc:2831 #2 0x0000555558d9fe59 in Query_result_send::send_result_set_metadata (this=0x7fff3429cfa0, thd=0x7fff34000c00, list=..., flags=5) at /home/greatdb/sql/query_result.cc:74 #3 0x0000555559093d1b in Query_expression::ExecuteIteratorQuery (this=0x7fff3429ae08, thd=0x7fff34000c00) at /home/greatdb/sql/sql_union.cc:1169 #4 0x0000555559094452 in Query_expression::execute (this=0x7fff3429ae08, thd=0x7fff34000c00) at /home/greatdb/sql/sql_union.cc:1305 #5 0x0000555558fd4b18 in Sql_cmd_dml::execute_inner (this=0x7fff3429cf68, thd=0x7fff34000c00) at /home/greatdb/sql/sql_select.cc:810 #6 0x0000555558fd3f24 in Sql_cmd_dml::execute (this=0x7fff3429cf68, thd=0x7fff34000c00) at /home/greatdb/sql/sql_select.cc:578 #7 0x0000555558f4ac03 in mysql_execute_command (thd=0x7fff34000c00, first_level=true) at /home/greatdb/sql/sql_parse.cc:4784 #8 0x0000555558f4cd80 in dispatch_sql_command (thd=0x7fff34000c00, parser_state=0x7fffe82ab990, update_userstat=false) at /home/greatdb/sql/sql_parse.cc:5384 #9 0x0000555558f42257 in dispatch_command (thd=0x7fff34000c00, com_data=0x7fffe82acb70, command=COM_QUERY) at /home/greatdb/sql/sql_parse.cc:1992 #10 0x0000555558f405c7 in do_command (thd=0x7fff34000c00) at /home/greatdb/sql/sql_parse.cc:1440 #11 0x0000555559163f7e in handle_connection (arg=0x55556091c920) at /home/greatdb/sql/conn_handler/connection_handler_per_thread.cc:307 #12 0x000055555ad85edf in pfs_spawn_thread (arg=0x5555607808c0) at /home/greatdb/storage/perfschema/pfs.cc:2899 #13 0x00007ffff77a6609 in start_thread (arg=) at pthread_create.c:477 #14 0x00007ffff76cb163 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95对于非表字段的内容显示格式取决于什么呢?继续找: mysql> select abcd from varb;输入该命令后找到相关字符显示的代码,对于非表字段的内容取决于结果是否STRING_RESULT,abcd属于Item_string,代码result_type()=STRING_RESULT,改造所以显示字符格式是服务器租用collation.collation。 class Item的成员函数如下: virtual const CHARSET_INFO *charset_for_protocol() { return result_type() == STRING_RESULT ? collation.collation : &my_charset_bin; }三、代码改造针对上面介绍的第一种情况改造代码如下: mysql> select * from varb; #class Field的成员函数改成如下,其中system_charset_info=my_charset_utf8_general_ci: const CHARSET_INFO *charset_for_protocol() const { return system_charset_info; }登录客户端,可以看到结果已经自动显示成字符格式而不是刚才看到的baniry格式。 mysql -h 127.0.0.1 -P3307 -uroot mysql> select * from varb; +------+------+ | id | bb | +------+------+ | 1 | abcd | +------+------+ 1 row in set (0.00 sec)四、总结MySQL客户端字符显示依赖charset_for_protocol()函数,可以根据自己的需求修改该函数的显示方式,方便自己的使用。如果未来新定义Item或者Field记得也要相应修改该函数来正确显示数据。亿华云 |