MySQL 8.0 GDB源码调试MySQL协议中客户端请求的分发

在下面函数上打上断点。

Protocol_classic::read_packet()
Protocol_classic::send_ok
do_command
Protocol_classic::get_command
dispatch_command
Protocol_classic::start_result_metadata
Protocol_classic::store_string
THD::send_result_set_row
Item::send
my_net_read

启动gdb

[root@ecs-test-node2 ~]# gdb -p $(pgrep -x mysqld)

(gdb) b Protocol_classic::read_packet()
Breakpoint 1 at 0x3ce2d10: file /data/mysql-8.0.42/sql/protocol_classic.cc, line 1410.
(gdb) b Protocol_classic::send_ok
Breakpoint 2 at 0x3ce2775: file /data/mysql-8.0.42/sql/protocol_classic.cc, line 1300.
(gdb) b do_command
Breakpoint 3 at 0x361c022: file /data/mysql-8.0.42/sql/sql_parse.cc, line 1311.
(gdb) b Protocol_classic::get_command
Breakpoint 4 at 0x3ce4002: file /data/mysql-8.0.42/sql/protocol_classic.cc, line 2993.
(gdb) b dispatch_command
Breakpoint 5 at 0x361cfbd: file /data/mysql-8.0.42/sql/sql_parse.cc, line 1690.
(gdb) b Protocol_classic::start_result_metadata
Breakpoint 6 at 0x3ce43c3: file /data/mysql-8.0.42/sql/protocol_classic.cc, line 3081.
(gdb) b Protocol_classic::store_string
Breakpoint 7 at 0x3ce50a3: file /data/mysql-8.0.42/sql/protocol_classic.cc, line 3425.
(gdb) b THD::send_result_set_row
Breakpoint 8 at 0x352fffa: file /data/mysql-8.0.42/sql/sql_class.cc, line 2887.
(gdb) b Item::send
Breakpoint 9 at 0x3a64ed7: file /data/mysql-8.0.42/sql/item.cc, line 7350.
(gdb) b my_net_read
Breakpoint 10 at 0x381aff3: file /data/mysql-8.0.42/sql-common/net_serv.cc, line 2268.
(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000003ce2d10 in Protocol_classic::read_packet() 
                                                   at /data/mysql-8.0.42/sql/protocol_classic.cc:1410
2       breakpoint     keep y   0x0000000003ce2775 in Protocol_classic::send_ok(unsigned int, unsigned int, unsigned long long, unsigned long long, char const*) at /data/mysql-8.0.42/sql/protocol_classic.cc:1300
3       breakpoint     keep y   0x000000000361c022 in do_command(THD*) at /data/mysql-8.0.42/sql/sql_parse.cc:1311
4       breakpoint     keep y   0x0000000003ce4002 in Protocol_classic::get_command(COM_DATA*, enum_server_command*) 
                                                   at /data/mysql-8.0.42/sql/protocol_classic.cc:2993
5       breakpoint     keep y   0x000000000361cfbd in dispatch_command(THD*, COM_DATA const*, enum_server_command) 
                                                   at /data/mysql-8.0.42/sql/sql_parse.cc:1690
6       breakpoint     keep y   0x0000000003ce43c3 in Protocol_classic::start_result_metadata(unsigned int, unsigned int, CHARSET_INFO const*) at /data/mysql-8.0.42/sql/protocol_classic.cc:3081
7       breakpoint     keep y   0x0000000003ce50a3 in Protocol_classic::store_string(char const*, unsigned long, CHARSET_INFO const*) at /data/mysql-8.0.42/sql/protocol_classic.cc:3425
8       breakpoint     keep y   0x000000000352fffa in THD::send_result_set_row(mem_root_deque<Item*> const&) 
                                                   at /data/mysql-8.0.42/sql/sql_class.cc:2887
9       breakpoint     keep y   0x0000000003a64ed7 in Item::send(Protocol*, String*) 
                                                   at /data/mysql-8.0.42/sql/item.cc:7350
10      breakpoint     keep y   0x000000000381aff3 in my_net_read(NET*) at /data/mysql-8.0.42/sql-common/net_serv.cc:2268

在另外一个终端,使用mysql连接DB。

[root@ecs-test-node2 ~]# mysql -h 192.168.0.100 -P 3315 -u lily -p -A
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
read_packet函数,用来读取客户端发过来的包。
(gdb) continue
Continuing.
[Switching to Thread 0x7f54a4268700 (LWP 1607978)]

Thread 35 "connection" hit Breakpoint 1, Protocol_classic::read_packet (this=0x7f542400c7f0)
    at /data/mysql-8.0.42/sql/protocol_classic.cc:1410
1410	  input_packet_length = my_net_read(&m_thd->net);

查看执行路径。

在login_connection建立连接后,会有native_password_authenticate等登陆验证的函数执行。

在parse_client_handshake_packet这个解析客户端握手包函数执行后,会来到read_packet函数。

(gdb) backtrace
#0  Protocol_classic::read_packet (this=0x7f542400c7f0) at /data/mysql-8.0.42/sql/protocol_classic.cc:1410
#1  0x00000000038d0a22 in parse_client_handshake_packet (thd=0x7f5424008990, mpvio=0x7f54a4267020, buff=0x7f54a4266b68, 
    pkt_len=32) at /data/mysql-8.0.42/sql/auth/sql_authentication.cc:2907
#2  0x00000000038d1b6f in server_mpvio_read_packet (param=0x7f54a4267020, buf=0x7f54a4266b68)
    at /data/mysql-8.0.42/sql/auth/sql_authentication.cc:3358
#3  0x00000000038d554e in native_password_authenticate (vio=0x7f54a4267020, info=0x7f54a4267048)
    at /data/mysql-8.0.42/sql/auth/sql_authentication.cc:4555
#4  0x00000000038d1d3e in do_auth_once (thd=0x7f5424008990, auth_plugin_name=..., mpvio=0x7f54a4267020)
    at /data/mysql-8.0.42/sql/auth/sql_authentication.cc:3403
#5  0x00000000038d350a in acl_authenticate (thd=0x7f5424008990, command=COM_CONNECT)
    at /data/mysql-8.0.42/sql/auth/sql_authentication.cc:3885
#6  0x0000000003594c53 in check_connection (thd=0x7f5424008990) at /data/mysql-8.0.42/sql/sql_connect.cc:652
#7  0x0000000003594e00 in login_connection (thd=0x7f5424008990) at /data/mysql-8.0.42/sql/sql_connect.cc:706
#8  0x0000000003595d29 in thd_prepare_connection (thd=0x7f5424008990) at /data/mysql-8.0.42/sql/sql_connect.cc:893
#9  0x000000000384457a in handle_connection (arg=0xc4025a0)
    at /data/mysql-8.0.42/sql/conn_handler/connection_handler_per_thread.cc:299
#10 0x00000000058bf53d in pfs_spawn_thread (arg=0xc402390) at /data/mysql-8.0.42/storage/perfschema/pfs.cc:3050
#11 0x00007f54cde821ca in start_thread (arg=<optimized out>) at pthread_create.c:479
#12 0x00007f54cc3a18d3 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

查看变量

(gdb) info local
__PRETTY_FUNCTION__ = "virtual int Protocol_classic::read_packet()"
(gdb) in args
Ambiguous command "in args": inf, inferior, info, init-if-undefined, inspect, internals, interpreter-exec, interrupt.
(gdb) info args
this = 0x7f542c0508b0
(gdb) print * this
$1 = {<Protocol> = {_vptr.Protocol = 0x87d3238 <vtable for Protocol_text+16>, m_previous_protocol = 0x0}, 
  m_client_capabilities = 3758096383, m_thd = 0x7f542c19a5a0, packet = 0x7f542c19c630, convert = {m_ptr = 0x0, 
    m_length = 0, m_charset = 0x88b7280 <my_charset_bin>, m_alloced_length = 0, m_is_alloced = false}, 
  field_pos = 1751318644, send_metadata = false, field_types = 0x0, count = 1970496882, field_count = 7566444, 
  sending_flags = 1918986339, input_packet_length = 0, 
  input_raw_packet = 0x6e6f697463656e6e <error: Cannot access memory at address 0x6e6f697463656e6e>, result_cs = 0x0, 
  bad_packet = true}

查看packet包里面的内容

(gdb) print *this.packet
$2 = {m_ptr = 0x7f542c1aeeb0 "", m_length = 0, m_charset = 0x88b7280 <my_charset_bin>, m_alloced_length = 16392, 
  m_is_alloced = true}
(gdb) print *this->packet
$3 = {m_ptr = 0x7f542c1aeeb0 "", m_length = 0, m_charset = 0x88b7280 <my_charset_bin>, m_alloced_length = 16392, 
  m_is_alloced = true}

(gdb) print *this->packet.m_charset
$4 = {number = 63, primary_number = 0, binary_number = 0, state = 817, csname = 0x76437e0 "binary", 
  m_coll_name = 0x76437e0 "binary", comment = 0x76437e7 "Binary pseudo charset", tailoring = 0x0, coll_param = 0x0, 
  ctype = 0x76435c0 <ctype_bin> "", to_lower = 0x76436e0 <bin_char_array> "", to_upper = 0x76436e0 <bin_char_array> "", 
  sort_order = 0x0, uca = 0x0, tab_to_uni = 0x0, tab_from_uni = 0x0, caseinfo = 0x8a1c9e0 <my_unicase_default>, 
  state_maps = 0xc08f3d0, ident_map = 0xc08f5d0 "", strxfrm_multiply = 1, caseup_multiply = 1 '\001', 
  casedn_multiply = 1 '\001', mbminlen = 1, mbmaxlen = 1, mbmaxlenlen = 1, min_sort_char = 0, max_sort_char = 255, 
  pad_char = 0 '\000', escape_with_backslash_is_dangerous = false, levels_for_compare = 1 '\001', 
  cset = 0x88b71a0 <my_charset_handler>, coll = 0x88b7140 <my_collation_binary_handler>, pad_attribute = NO_PAD}

打印线程结构体

(gdb) print this->m_thd
$14 = (THD *) 0x7f542c19a5a0
(gdb) print *this->m_thd
$15 = {<MDL_context_owner> = {_vptr.MDL_context_owner = 0x86ecb00 <vtable for THD+16>}, <Query_arena> = {
    _vptr.Query_arena = 0x86ecb70 <vtable for THD+128>, m_item_list = 0x0, mem_root = 0x7f542c19ced0, 
    is_repreparing = false, state = Query_arena::STMT_REGULAR_EXECUTION}, <Open_tables_state> = {
    m_reprepare_observers = {static Has_trivial_destructor = <optimized out>, static initial_capacity = <optimized out>, 
      m_psi_key = 0, m_inline_size = 0, {m_ext = {m_array_ptr = 0x0, m_alloced_size = 0, m_alloced_capacity = 0}, 
        m_buff = {0x0, 0x0, 0x0, 0x0}}}, open_tables = 0x0, temporary_tables = 0x0, lock = 0x0, extra_lock = 0x0, 
    locked_tables_mode = LTM_NONE, state_flags = 0}, m_mem_cnt = {m_enabled = true, m_thd = 0x7f542c19a5a0, m_da = {
      m_stacked_da = 0x0, m_condition_root = {static s_dummy_target = 0 '\000', m_current_block = 0x0, 
        m_current_free_start = 0x8cb2350 <MEM_ROOT::s_dummy_target> "", 
        m_current_free_end = 0x8cb2350 <MEM_ROOT::s_dummy_target> "", m_block_size = 2048, m_orig_block_size = 2048, 
        m_max_capacity = 0, m_allocated_size = 0, m_error_for_capacity_exceeded = false, m_error_handler = 0x34f935d
     <sql_alloc_error_handler()>, m_psi_key = 0}, m_conditions_list = {<I_P_List_counter> = {
          m_counter = 0}, <I_P_List_fast_push_back<Sql_condition>> = {m_last = 0x7f542c19a690}, m_first = 0x0}, 
      m_preexisting_sql_conditions = {<base_list> = {first = 0x8c08d70 <end_of_list>, last = 0x7f542c19a698, 
          elements = 0}, <No data fields>}, m_is_sent = false, m_can_overwrite_status = false, 
      m_allow_unlimited_conditions = false, m_status = Diagnostics_area::DA_EMPTY, 
      m_message_text = "\000d=1;row_type=2;stats_auto_recalc=0;stats_persistent=0;stats_sample_pages=0;\000\000\000\000", '\337' <repeats 16 times>, '\000' <repeats 415 times>, m_message_text_length = 0, 
      m_returned_sqlstate = "\000\000\000\000\000", m_mysql_errno = 0, m_affected_rows = 0, m_last_insert_id = 0, 
      m_last_statement_cond_count = 0, m_current_statement_cond_count = 0, m_current_statement_cond_count_by_qb = {0, 0, 
        0}, m_current_row_for_condition = 1, m_saved_error_count = 0, m_saved_warn_count = 0}, mem_counter = 8240, 
    max_conn_mem = 8240, glob_mem_counter = 0, curr_mode = 0, orig_mode = 0, is_connection_stage = true}, mdl_context = {
    m_wait = {m_LOCK_wait_status = {m_mutex = {m_u = {m_native = {__data = {__lock = 739830096, __count = 32596, 
                __owner = 0, __nusers = 0, __kind = 0, __spins = 0, __elision = 0, __list = {__prev = 0x0, 
                  __next = 0x0}}, __size = "P\351\030,T\177", '\000' <repeats 33 times>, __align = 139999493810512}, 
            m_safe_ptr = 0x7f542c18e950}}, m_psi = 0xc21cfa0}, m_COND_wait_status = {m_cond = {__data = {{__wseq = 0, 
              __wseq32 = {__low = 0, __high = 0}}, {__g1_start = 0, __g1_start32 = {__low = 0, __high = 0}}, 
            __glibc_unused___g_refs = {0, 0}, __g_size = {0, 0}, __g1_orig_size = 0, __wrefs = 0, __g_signals = {0, 0}}, 
          __size = '\000' <repeats 47 times>, __align = 0}, m_psi = 0xc010c58}, m_wait_status = MDL_wait::WS_EMPTY}, 
    m_ticket_store = {m_durations = {{
          m_ticket_list = {<I_P_List_null_counter> = {<No data fields>}, <I_P_List_no_push_back<MDL_ticket>> = {<No data fields>}, m_first = 0x0}, m_mat_front = 0x0}, {
          m_ticket_list = {<I_P_List_null_counter> = {<No data fields>}, <I_P_List_no_push_back<MDL_ticket>> = {<No data f--Type <RET> for more, q to quit, c to continue without paging--q
Quit

read_packet的函数定义

int Protocol_classic::read_packet() {
  input_packet_length = my_net_read(&m_thd->net);
  if (input_packet_length != packet_error) {
    assert(!m_thd->net.error);
    bad_packet = false;
    input_raw_packet = m_thd->net.read_pos;
    return 0;
  }

  bad_packet = true;
  return m_thd->net.error == NET_ERROR_SOCKET_UNUSABLE ? 1 : -1;
}

继续调试后面的断点。

(gdb) continue
Continuing.

Thread 36 "connection" hit Breakpoint 10, my_net_read (net=0x7f542c19c398)
    at /data/mysql-8.0.42/sql-common/net_serv.cc:2268
2268	  if (!vio_is_blocking(net->vio)) vio_set_blocking_flag(net->vio, true);
(gdb) backtrace
#0  my_net_read (net=0x7f542c19c398) at /data/mysql-8.0.42/sql-common/net_serv.cc:2268
#1  0x0000000003ce2d26 in Protocol_classic::read_packet (this=0x7f542c0508b0)
    at /data/mysql-8.0.42/sql/protocol_classic.cc:1410
#2  0x00000000038d1aec in server_mpvio_read_packet (param=0x7f54a4165020, buf=0x7f54a4164b68)
    at /data/mysql-8.0.42/sql/auth/sql_authentication.cc:3344
#3  0x00000000038d554e in native_password_authenticate (vio=0x7f54a4165020, info=0x7f54a4165048)
    at /data/mysql-8.0.42/sql/auth/sql_authentication.cc:4555
#4  0x00000000038d1d3e in do_auth_once (thd=0x7f542c19a5a0, auth_plugin_name=..., mpvio=0x7f54a4165020)
    at /data/mysql-8.0.42/sql/auth/sql_authentication.cc:3403
#5  0x00000000038d350a in acl_authenticate (thd=0x7f542c19a5a0, command=COM_CONNECT)
    at /data/mysql-8.0.42/sql/auth/sql_authentication.cc:3885
#6  0x0000000003594c53 in check_connection (thd=0x7f542c19a5a0) at /data/mysql-8.0.42/sql/sql_connect.cc:652
#7  0x0000000003594e00 in login_connection (thd=0x7f542c19a5a0) at /data/mysql-8.0.42/sql/sql_connect.cc:706
#8  0x0000000003595d29 in thd_prepare_connection (thd=0x7f542c19a5a0) at /data/mysql-8.0.42/sql/sql_connect.cc:893
#9  0x000000000384457a in handle_connection (arg=0xc448c60)
    at /data/mysql-8.0.42/sql/conn_handler/connection_handler_per_thread.cc:299
#10 0x00000000058bf53d in pfs_spawn_thread (arg=0xc430ac0) at /data/mysql-8.0.42/storage/perfschema/pfs.cc:3050
#11 0x00007f54cde821ca in start_thread (arg=<optimized out>) at pthread_create.c:479
#12 0x00007f54cc3a18d3 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
my_net_read用于读取客户端/服务端发过来的包,返回的时候不带有内部的包头。
/**
  Read a packet from the client/server and return it without the internal
  package header.
*/

ulong my_net_read(NET *net) {
  size_t len;
  /* turn off non blocking operations */
  if (!vio_is_blocking(net->vio)) vio_set_blocking_flag(net->vio, true);

  if (net->compress)
    net_read_compressed_packet(net, len);
  else
    net_read_uncompressed_packet(net, len);

  return static_cast<ulong>(len);
}

查看net结构体。

(gdb) info local
len = 140001506904768
(gdb) info args
net = 0x7f542c19c398
(gdb) print *net
$16 = {vio = 0x7f542c050960, buff = 0x7f542c069700 "P", buff_end = 0x7f542c06d700 "0@", write_pos = 0x7f542c069700 "P", 
  read_pos = 0x6e6f697463656e6e <error: Cannot access memory at address 0x6e6f697463656e6e>, fd = 37, remain_in_buf = 0, 
  length = 0, buf_length = 0, where_b = 0, max_packet = 16384, max_packet_size = 1073741824, pkt_nr = 1, 
  compress_pkt_nr = 0, write_timeout = 10, read_timeout = 10, retry_count = 10, fcntl = 0, return_status = 0x0, 
  reading_or_writing = 0 '\000', save_char = 0 '\000', compress = false, last_errno = 0, error = 0 '\000', 
  last_error = '\000' <repeats 511 times>, sqlstate = "\000\000\000\000\000", extension = 0x7f542c19ab90}
(gdb) print *net.buff
$17 = 80 'P'
(gdb) print *net.buff_end
$18 = 48 '0'
(gdb) print *net.write_pos
$19 = 80 'P'

(gdb) print *net.vio
$20 = {mysql_socket = {fd = 37, m_psi = 0xc22aed8}, localhost = false, type = VIO_TYPE_TCPIP, read_timeout = 10000, 
  write_timeout = 10000, retry_count = 1, inactive = false, local = {ss_family = 0, 
    __ss_padding = '\000' <repeats 117 times>, __ss_align = 0}, remote = {ss_family = 2, 
    __ss_padding = "\241\062\300\250\000d", '\000' <repeats 111 times>, __ss_align = 0}, addrLen = 16, 
  read_buffer = 0x0, read_pos = 0x0, read_end = 0x0, thread_id = std::optional [no contained value], signal_mask = {
    __val = {543239, 0 <repeats 15 times>}}, poll_shutdown_flag = {<std::__atomic_flag_base> = {
      _M_i = false}, <No data fields>}, network_namespace = '\000' <repeats 255 times>, viodelete = 0x5c24a4b
     <vio_delete(Vio*)>, vioerrno = 0x5c254d9 <vio_errno(Vio*)>, 
  read = 0x5c2558b <vio_read(Vio*, unsigned char*, unsigned long)>, 
  write = 0x5c259ba <vio_write(Vio*, unsigned char const*, unsigned long)>, 
  timeout = 0x5c25d6d <vio_socket_timeout(Vio*, unsigned int, bool)>, 
  viokeepalive = 0x5c25f56 <vio_keepalive(Vio*, bool)>, fastsend = 0x5c25e2a <vio_fastsend(Vio*)>, 
  peer_addr = 0x5c26779 <vio_peer_addr(Vio*, char*, unsigned short*, unsigned long)>, in_addr = 0x0, 
  should_retry = 0x5c2606e <vio_should_retry(Vio*)>, was_timeout = 0x5c2608e <vio_was_timeout(Vio*)>, 
  vioshutdown = 0x5c260e0 <vio_shutdown(Vio*)>, is_connected = 0x5c27160 <vio_is_connected(Vio*)>, 
  has_data = 0x5c2369c <has_no_data(Vio*)>, io_wait = 0x5c26af9 <vio_io_wait(Vio*, enum_vio_io_event, int)>, 
  connect = 0x0, ssl_arg = 0x0, m_psi_read_locker = 0x0, m_psi_read_state = {m_flags = 738528440, m_socket = 0x0, 
    m_thread = 0x7f530000004f, m_number_of_bytes = 0, m_timer_start = 0, m_timer = 0x7f542c050ce8, 
    m_operation = 738528488, m_src_file = 0x0, m_src_line = 800, m_wait = 0xb1}, m_psi_write_locker = 0x0, 
  m_psi_write_state = {m_flags = 739948384, m_socket = 0x7f54c5dafc40, m_thread = 0x91, 
    m_number_of_bytes = 1752346657176, m_timer_start = 0, m_timer = 0x7f54cd9af6e0 <eckey_asn1_meth>, 
    m_operation = PSI_SOCKET_CREATE, m_src_file = 0x0, m_src_line = 0, m_wait = 0x1}, 
  is_blocking = 0x5c25d22 <vio_is_blocking(Vio*)>, set_blocking = 0x5c25b31 <vio_set_blocking(Vio*, bool)>, 
  set_blocking_flag = 0x5c25c28 <vio_set_blocking_flag(Vio*, bool)>, is_blocking_flag = true}

继续调试后续的代码。

(gdb) continue
Continuing.

Thread 36 "connection" hit Breakpoint 1, Protocol_classic::read_packet (this=0x7f542c0508b0)
    at /data/mysql-8.0.42/sql/protocol_classic.cc:1410
1410	  input_packet_length = my_net_read(&m_thd->net);
(gdb) info args
this = 0x7f542c0508b0
(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 10, my_net_read (net=0x7f542c19c398)
    at /data/mysql-8.0.42/sql-common/net_serv.cc:2268
2268	  if (!vio_is_blocking(net->vio)) vio_set_blocking_flag(net->vio, true);
(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 2, Protocol_classic::send_ok (this=0x7f542c0508b0, server_status=2, 
    statement_warn_count=0, affected_rows=0, last_insert_id=0, message=0x7f542c19cfb0 "")
    at /data/mysql-8.0.42/sql/protocol_classic.cc:1300
1300	  DBUG_TRACE;
Protocol_classic::send_ok函数负责服务端传输OK响应包给客户端。
/**
  A default implementation of "OK" packet response to the client.

  Currently this implementation is re-used by both network-oriented
  protocols -- the binary and text one. They do not differ
  in their OK packet format, which allows for a significant simplification
  on client side.
*/

bool Protocol_classic::send_ok(uint server_status, uint statement_warn_count,
                               ulonglong affected_rows,
                               ulonglong last_insert_id, const char *message) {
  DBUG_TRACE;
  const bool retval =
      net_send_ok(m_thd, server_status, statement_warn_count, affected_rows,
                  last_insert_id, message, false);
  // Reclaim some memory
  convert.shrink(m_thd->variables.net_buffer_length);
  return retval;
}

对应的执行路径。

(gdb) backtrace
#0  Protocol_classic::send_ok (this=0x7f542c0508b0, server_status=2, statement_warn_count=0, affected_rows=0, 
    last_insert_id=0, message=0x7f542c19cfb0 "") at /data/mysql-8.0.42/sql/protocol_classic.cc:1300
#1  0x00000000035304c6 in THD::send_statement_status (this=0x7f542c19a5a0) at /data/mysql-8.0.42/sql/sql_class.cc:2927
#2  0x0000000003594e0f in login_connection (thd=0x7f542c19a5a0) at /data/mysql-8.0.42/sql/sql_connect.cc:707
#3  0x0000000003595d29 in thd_prepare_connection (thd=0x7f542c19a5a0) at /data/mysql-8.0.42/sql/sql_connect.cc:893
#4  0x000000000384457a in handle_connection (arg=0xc448c60)
    at /data/mysql-8.0.42/sql/conn_handler/connection_handler_per_thread.cc:299
#5  0x00000000058bf53d in pfs_spawn_thread (arg=0xc430ac0) at /data/mysql-8.0.42/storage/perfschema/pfs.cc:3050
#6  0x00007f54cde821ca in start_thread (arg=<optimized out>) at pthread_create.c:479
#7  0x00007f54cc3a18d3 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

继续后续的调试。

(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 3, do_command (thd=0x7f542c19a5a0) at /data/mysql-8.0.42/sql/sql_parse.cc:1311
1311	  NET *net = nullptr;
(gdb) backtrace
#0  do_command (thd=0x7f542c19a5a0) at /data/mysql-8.0.42/sql/sql_parse.cc:1311
#1  0x0000000003844598 in handle_connection (arg=0xc448c60)
    at /data/mysql-8.0.42/sql/conn_handler/connection_handler_per_thread.cc:303
#2  0x00000000058bf53d in pfs_spawn_thread (arg=0xc430ac0) at /data/mysql-8.0.42/storage/perfschema/pfs.cc:3050
#3  0x00007f54cde821ca in start_thread (arg=<optimized out>) at pthread_create.c:479
#4  0x00007f54cc3a18d3 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb) info local
return_value = false
rc = 739878304
net = 0x7f54000000df
command = COM_SLEEP
com_data = {com_init_db = {db_name = 0x7f54a4165a80 "\260Z\026\244T\177", length = 55460967}, com_refresh = {
    options = 128 '\200'}, com_kill = {id = 140001506908800}, com_set_option = {opt_command = 2752928384}, 
  com_stmt_execute = {stmt_id = 140001506908800, open_cursor = 55460967, parameters = 0x8c03f40 <connection_attrib>, 
    parameter_count = 139999493868308, has_new_types = 176 '\260'}, com_stmt_fetch = {stmt_id = 140001506908800, 
    num_rows = 55460967}, com_stmt_send_long_data = {stmt_id = 140001506908800, param_number = 55460967, 
    longdata = 0x8c03f40 <connection_attrib> "", length = 139999493868308}, com_stmt_prepare = {
    query = 0x7f54a4165a80 "\260Z\026\244T\177", length = 55460967}, com_stmt_close = {stmt_id = 2752928384}, 
  com_stmt_reset = {stmt_id = 2752928384}, com_query = {query = 0x7f54a4165a80 "\260Z\026\244T\177", length = 55460967, 
    parameters = 0x8c03f40 <connection_attrib>, parameter_count = 139999493868308}, com_field_list = {
    table_name = 0x7f54a4165a80 "\260Z\026\244T\177", table_name_length = 55460967, 
    query = 0x8c03f40 <connection_attrib> "", query_length = 739887892}}
_db_trace = {m_stack_frame = {func = 0x7f54a4165a60 "\200Z\026\244T\177", func_len = 55462929, 
    file = 0x500000005 <error: Cannot access memory at address 0x500000005>, level = 739887892, prev = 0x72cd953}}
__PRETTY_FUNCTION__ = "bool do_command(THD*)"
query_start_status = {created_tmp_disk_tables = 140001871885264, created_tmp_tables = 140001871885264, 
  ha_commit_count = 140001506907072, ha_delete_count = 93223725, ha_read_first_count = 140001506907256, 
  ha_read_last_count = 140001882016256, ha_read_key_count = 140001506907120, ha_read_next_count = 5954958927198244352, 
  ha_read_prev_count = 140001506907256, ha_read_rnd_count = 202066864, ha_read_rnd_next_count = 140001506907168, 
  ha_multi_range_read_init_count = 1, ha_rollback_count = 139999493863680, ha_update_count = 146816832, 
  ha_write_count = 140001506909248, ha_prepare_count = 63438843, ha_discover_count = 139999492204256, 
  ha_savepoint_count = 1, ha_savepoint_rollback_count = 140001506907200, ha_external_lock_count = 54875113, 
  opened_tables = 140001506907256, opened_shares = 140001506907264, table_open_cache_hits = 140001506907760, 
  table_open_cache_misses = 63428291, table_open_cache_overflows = 140001506907408, 
  select_full_join_count = 139999493899952, select_full_range_join_count = 8589934592, 
  select_range_count = 139999493859632, select_range_check_count = 140001506907456, select_scan_count = 1, 
  long_query_count = 120379725, filesort_merge_passes = 0, filesort_range_count = 120379731, filesort_rows = 2147483649, 
  filesort_scan_count = 0, com_stmt_prepare = 56813002, com_stmt_reprepare = 0, com_stmt_execute = 0, 
  com_stmt_send_long_data = 0, com_stmt_fetch = 0, com_stmt_reset = 0, com_stmt_close = 0, bytes_received = 0, 
  bytes_sent = 0, max_execution_time_exceeded = 0, max_execution_time_set = 0, max_execution_time_set_failed = 0, 
--Type <RET> for more, q to quit, c to continue without paging--q
questionQuit
(gdb) info args
thd = 0x7f542c19a5a0
(gdb) print *thd 
$25 = {<MDL_context_owner> = {_vptr.MDL_context_owner = 0x86ecb00 <vtable for THD+16>}, <Query_arena> = {
    _vptr.Query_arena = 0x86ecb70 <vtable for THD+128>, m_item_list = 0x0, mem_root = 0x7f542c19ced0, 
    is_repreparing = false, state = Query_arena::STMT_REGULAR_EXECUTION}, <Open_tables_state> = {
    m_reprepare_observers = {static Has_trivial_destructor = <optimized out>, static initial_capacity = <optimized out>, 
      m_psi_key = 0, m_inline_size = 0, {m_ext = {m_array_ptr = 0x0, m_alloced_size = 0, m_alloced_capacity = 0}, 
        m_buff = {0x0, 0x0, 0x0, 0x0}}}, open_tables = 0x0, temporary_tables = 0x0, lock = 0x0, extra_lock = 0x0, 
    locked_tables_mode = LTM_NONE, state_flags = 0}, m_mem_cnt = {m_enabled = true, m_thd = 0x7f542c19a5a0, m_da = {
      m_stacked_da = 0x0, m_condition_root = {static s_dummy_target = 0 '\000', m_current_block = 0x0, 
        m_current_free_start = 0x8cb2350 <MEM_ROOT::s_dummy_target> "", 
        m_current_free_end = 0x8cb2350 <MEM_ROOT::s_dummy_target> "", m_block_size = 2048, m_orig_block_size = 2048, 
        m_max_capacity = 0, m_allocated_size = 0, m_error_for_capacity_exceeded = false, 
        m_error_handler = 0x34f935d <sql_alloc_error_handler()>, m_psi_key = 0}, 
      m_conditions_list = {<I_P_List_counter> = {m_counter = 0}, <I_P_List_fast_push_back<Sql_condition>> = {
          m_last = 0x7f542c19a690}, m_first = 0x0}, m_preexisting_sql_conditions = {<base_list> = {
          first = 0x8c08d70 <end_of_list>, last = 0x7f542c19a698, elements = 0}, <No data fields>}, m_is_sent = false, 
      m_can_overwrite_status = false, m_allow_unlimited_conditions = false, m_status = Diagnostics_area::DA_EMPTY, 
      m_message_text = "\000d=1;row_type=2;stats_auto_recalc=0;stats_persistent=0;stats_sample_pages=0;\000\000\000\000", '\337' <repeats 16 times>, '\000' <repeats 415 times>, m_message_text_length = 0, 
      m_returned_sqlstate = "\000\000\000\000\000", m_mysql_errno = 0, m_affected_rows = 0, m_last_insert_id = 0, 
      m_last_statement_cond_count = 0, m_current_statement_cond_count = 0, m_current_statement_cond_count_by_qb = {0, 0, 
        0}, m_current_row_for_condition = 1, m_saved_error_count = 0, m_saved_warn_count = 0}, mem_counter = 8240, 
    max_conn_mem = 8240, glob_mem_counter = 0, curr_mode = 0, orig_mode = 7, is_connection_stage = true}, mdl_context = {
    m_wait = {m_LOCK_wait_status = {m_mutex = {m_u = {m_native = {__data = {__lock = 739830096, __count = 32596, 
                __owner = 0, __nusers = 0, __kind = 0, __spins = 0, __elision = 0, __list = {__prev = 0x0, 
                  __next = 0x0}}, __size = "P\351\030,T\177", '\000' <repeats 33 times>, __align = 139999493810512}, 
            m_safe_ptr = 0x7f542c18e950}}, m_psi = 0xc21cfa0}, m_COND_wait_status = {m_cond = {__data = {{__wseq = 0, 
              __wseq32 = {__low = 0, __high = 0}}, {__g1_start = 0, __g1_start32 = {__low = 0, __high = 0}}, 
            __glibc_unused___g_refs = {0, 0}, __g_size = {0, 0}, __g1_orig_size = 0, __wrefs = 0, __g_signals = {0, 0}}, 
          __size = '\000' <repeats 47 times>, __align = 0}, m_psi = 0xc010c58}, m_wait_status = MDL_wait::WS_EMPTY}, 
    m_ticket_store = {m_durations = {{
          m_ticket_list = {<I_P_List_null_counter> = {<No data fields>}, <I_P_List_no_push_back<MDL_ticket>> = {<No data fields>}, m_first = 0x0}, m_mat_front = 0x0}, {
          m_ticket_list = {<I_P_List_null_counter> = {<No data fields>}, <I_P_List_no_push_back<MDL_ticket>> = {<No data f--Type <RET> for more, q to quit, c to continue without paging--q
Quit
do_command函数会从连接中读取一个命令并执行。
/**
  Read one command from connection and execute it (query or simple command).
  This function is called in loop from thread function.

  For profiling to work, it must never be called recursively.

  @retval
    0  success
  @retval
    1  request of thread shutdown (see dispatch_command() description)
*/

bool do_command(THD *thd) {
  bool return_value;
  int rc;
  NET *net = nullptr;
  enum enum_server_command command = COM_SLEEP;
  COM_DATA com_data;
  DBUG_TRACE;
  assert(thd->is_classic_protocol());

  /*
    indicator of uninitialized lex => normal flow of errors handling
    (see my_message_sql)
  */
  thd->lex->set_current_query_block(nullptr);
..

打印command变量,刚进入函数,里面的值是COM_SLEEP。

(gdb) print command
$26 = COM_SLEEP

继续调试后续的代码。

(gdb) next
1312	  enum enum_server_command command = COM_SLEEP;
(gdb) n
1314	  DBUG_TRACE;
(gdb) n
1315	  assert(thd->is_classic_protocol());
(gdb) print command
$30 = COM_SLEEP
(gdb) n
1321	  thd->lex->set_current_query_block(nullptr);
(gdb) print command
$31 = COM_SLEEP
(gdb) n
1329	  thd->clear_error();  // Clear error message
(gdb) n
1330	  thd->get_stmt_da()->reset_diagnostics_area();
(gdb) print command
$32 = COM_SLEEP
(gdb) n
1338	  net = thd->get_protocol_classic()->get_net();
(gdb) print command
$33 = COM_SLEEP
(gdb) n
1339	  my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
(gdb) print command
$34 = COM_SLEEP
(gdb) n
1340	  net_new_transaction(net);
(gdb) print command
$35 = COM_SLEEP
(gdb) n
1356	  DEBUG_SYNC(thd, "before_do_command_net_read");
(gdb) n
1360	  thd->clear_copy_status_var();
(gdb) n
1361	  if (opt_log_slow_extra) {
(gdb) print command
$36 = COM_SLEEP
(gdb) n
1365	  rc = thd->m_mem_cnt.reset();
(gdb) print command
$37 = COM_SLEEP
(gdb) n
1366	  if (rc)
(gdb) n
1380	    thd->m_server_idle = true;
(gdb) n
1381	    rc = thd->get_protocol()->get_command(&com_data, &command);
(gdb) n

Thread 36 "connection" hit Breakpoint 4, Protocol_classic::get_command (this=0x7f542c0508b0, com_data=0x7f54a4165a60, 
    cmd=0x7f54a4165a8c) at /data/mysql-8.0.42/sql/protocol_classic.cc:2993
2993	  if (int rc = read_packet()) return rc;
(gdb) print command
No symbol "command" in current context.
(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 1, Protocol_classic::read_packet (this=0x7f542c0508b0)
    at /data/mysql-8.0.42/sql/protocol_classic.cc:1410
1410	  input_packet_length = my_net_read(&m_thd->net);
(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 10, my_net_read (net=0x7f542c19c398)
    at /data/mysql-8.0.42/sql-common/net_serv.cc:2268
2268	  if (!vio_is_blocking(net->vio)) vio_set_blocking_flag(net->vio, true);
Protocol_classic::get_command函数会解析包中的命令。
int Protocol_classic::get_command(COM_DATA *com_data,
                                  enum_server_command *cmd) {
  // read packet from the network
  if (int rc = read_packet()) return rc;

  /*
    'input_packet_length' contains length of data, as it was stored in packet
    header. In case of malformed header, my_net_read returns zero.
    If input_packet_length is not zero, my_net_read ensures that the returned
    number of bytes was actually read from network.
    There is also an extra safety measure in my_net_read:
    it sets packet[input_packet_length]= 0, but only for non-zero packets.
  */
  if (input_packet_length == 0) /* safety */
  {
    /* Initialize with COM_SLEEP packet */
    input_raw_packet[0] = (uchar)COM_SLEEP;
    input_packet_length = 1;
  }
  /* Do not rely on my_net_read, extra safety against programming errors. */
  input_raw_packet[input_packet_length] = '\0'; /* safety */

  *cmd = (enum enum_server_command)(uchar)input_raw_packet[0];

  if (*cmd >= COM_END) *cmd = COM_END;  // Wrong command

  assert(input_packet_length);
  // Skip 'command'
  input_packet_length--;
  input_raw_packet++;

  return parse_packet(com_data, *cmd);
}

接着调试后续的代码。

(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 5, dispatch_command (thd=0x7f542c19a5a0, com_data=0x7f54a4165a60, 
    command=COM_QUERY) at /data/mysql-8.0.42/sql/sql_parse.cc:1690
1690	  assert(thd->lex->m_IS_table_stats.is_valid() == false);
(gdb) info local
__PRETTY_FUNCTION__ = "bool dispatch_command(THD*, const COM_DATA*, enum_server_command)"
tabstat_grd = {m_is_released = 114, m_cleanup_lambda = {__thd = @0x160000ffff}}
error = false
thd_manager = 0x0
_db_trace = {m_stack_frame = {func = 0x4018 <error: Cannot access memory at address 0x4018>, func_len = -868212155, 
    file = 0x0, level = 0, prev = 0x7f54a4165170}}
clone_cmd = 0x65ade7c
__FUNCTION__ = "dispatch_command"
__func__ = "dispatch_command"
cn = "my_net_set_read_timeout"
kPreallocSz = 0
(gdb) info args
thd = 0x7f542c19a5a0
com_data = 0x7f54a4165a60
command = COM_QUERY

(gdb) bt
#0  dispatch_command (thd=0x7f542c19a5a0, com_data=0x7f54a4165a60, command=COM_QUERY)
    at /data/mysql-8.0.42/sql/sql_parse.cc:1690
#1  0x000000000361c5ca in do_command (thd=0x7f542c19a5a0) at /data/mysql-8.0.42/sql/sql_parse.cc:1440
#2  0x0000000003844598 in handle_connection (arg=0xc448c60)
    at /data/mysql-8.0.42/sql/conn_handler/connection_handler_per_thread.cc:303
#3  0x00000000058bf53d in pfs_spawn_thread (arg=0xc430ac0) at /data/mysql-8.0.42/storage/perfschema/pfs.cc:3050
#4  0x00007f54cde821ca in start_thread (arg=<optimized out>) at pthread_create.c:479
#5  0x00007f54cc3a18d3 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
dispatch_command函数会执行连接中发送过来的命令。
/**
  Perform one connection-level (COM_XXXX) command.

  @param thd             connection handle
  @param command         type of command to perform
  @param com_data        com_data union to store the generated command

  @todo
    set thd->lex->sql_command to SQLCOM_END here.
  @todo
    The following has to be changed to an 8 byte integer

  @retval
    0   ok
  @retval
    1   request of thread shutdown, i. e. if command is
        COM_QUIT
*/
bool dispatch_command(THD *thd, const COM_DATA *com_data,
                      enum enum_server_command command) {
  assert(thd->lex->m_IS_table_stats.is_valid() == false);
  assert(thd->lex->m_IS_tablespace_stats.is_valid() == false);
..

这个时候command变量的值是COM_QUERY,去处理一个查询请求。

(gdb) print command
$38 = COM_QUERY

继续后续的调试。

(gdb) n
1691	  assert(thd->lex->m_IS_tablespace_stats.is_valid() == false);
(gdb) n
1696	  });
(gdb) n
1698	  bool error = false;
(gdb) n
1699	  Global_THD_manager *thd_manager = Global_THD_manager::get_instance();
(gdb) n
1700	  DBUG_TRACE;
(gdb) n
1701	  DBUG_PRINT("info", ("command: %d", command));
(gdb) n
1703	  Sql_cmd_clone *clone_cmd = nullptr;
(gdb) n
1707	  thd->profiling->start_new_query();
(gdb) n
1711	  thd->m_statement_psi = MYSQL_REFINE_STATEMENT(
(gdb) n
1714	  thd->set_command(command);
(gdb) n
1719	  thd->enable_slow_log = true;
(gdb) n
1720	  thd->lex->sql_command = SQLCOM_END; /* to avoid confusing VIEW detectors */
(gdb) n
1730	  if (thd->killed == THD::KILL_QUERY) thd->killed = THD::NOT_KILLED;
(gdb) n
1731	  thd->set_time();
(gdb) n
1732	  if (is_time_t_valid_for_timestamp(thd->query_start_in_secs()) == false) {
(gdb) n
1768	  thd->set_query_id(next_query_id());
(gdb) n
1769	  thd->reset_rewritten_query();
(gdb) n
1770	  thd_manager->inc_thread_running();
(gdb) n
1772	  if (!(server_command_flags[command] & CF_SKIP_QUESTIONS))
(gdb) n
1773	    thd->status_var.questions++;
(gdb) n
1779	  thd->server_status &= ~SERVER_STATUS_CLEAR_SET;
(gdb) n
1781	  if (thd->get_protocol()->type() == Protocol::PROTOCOL_PLUGIN &&
(gdb) n
1800	  if (unlikely(thd->security_context()->password_expired() &&
(gdb) 
1803	               command != COM_QUIT && command != COM_STMT_PREPARE &&
(gdb) n
1800	  if (unlikely(thd->security_context()->password_expired() &&
(gdb) 
1810	                         Command_names::str_global(command).c_str())) {
(gdb) 
1809	  if (mysql_audit_notify(thd, AUDIT_EVENT(MYSQL_AUDIT_COMMAND_START), command,
(gdb) 
1814	  switch (command) {
(gdb) n
2012	      assert(thd->m_digest == nullptr);
(gdb) n
2013	      thd->m_digest = &thd->m_digest_state;
(gdb) n
2014	      thd->m_digest->reset(thd->m_token_array, max_digest_length);
(gdb) n
2017	                      com_data->com_query.length))
(gdb) n
2016	      if (alloc_query(thd, com_data->com_query.query,
(gdb) n
2020	      const char *packet_end = thd->query().str + thd->query().length;
(gdb) n
2022	      if (opt_general_log_raw)
(gdb) n
2026	      DBUG_PRINT("query", ("%-.4096s", thd->query().str));
(gdb) n
2029	      thd->profiling->set_query_source(thd->query().str, thd->query().length);
(gdb) n
2032	      const LEX_CSTRING orig_query = thd->query();
(gdb) n
2034	      Parser_state parser_state;
(gdb) n
2035	      if (parser_state.init(thd, thd->query().str, thd->query().length)) break;
(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 6, Protocol_classic::start_result_metadata (this=0x7f542c0508b0, num_cols_arg=1, 
    flags=5, cs=0x8a09400 <my_charset_utf8mb4_0900_ai_ci>) at /data/mysql-8.0.42/sql/protocol_classic.cc:3081
3081	  DBUG_TRACE;

(gdb) info args
this = 0x7f542c0508b0
num_cols_arg = 1
flags = 5
cs = 0x8a09400 <my_charset_utf8mb4_0900_ai_ci>
(gdb) print *cs
$39 = {number = 255, primary_number = 0, binary_number = 0, state = 17377, csname = 0x785420e "utf8mb4", 
  m_coll_name = 0x78548a0 "utf8mb4_0900_ai_ci", comment = 0x7854051 "UTF-8 Unicode", tailoring = 0x0, coll_param = 0x0, 
  ctype = 0x7853f20 <ctype_utf8> "", to_lower = 0x0, to_upper = 0x0, sort_order = 0x0, uca = 0x89f9600 <my_uca_v900>, 
  tab_to_uni = 0x0, tab_from_uni = 0x0, caseinfo = 0x89f95e0 <my_unicase_unicode900>, state_maps = 0xc0a0dd0, 
  ident_map = 0xc0a0fd0 "", strxfrm_multiply = 0, caseup_multiply = 1 '\001', casedn_multiply = 1 '\001', mbminlen = 1, 
  mbmaxlen = 4, mbmaxlenlen = 1, min_sort_char = 9, max_sort_char = 1114111, pad_char = 32 ' ', 
  escape_with_backslash_is_dangerous = false, levels_for_compare = 1 '\001', 
  cset = 0x8a26a60 <my_charset_utf8mb4_handler>, coll = 0x8a03da0 <my_collation_uca_900_handler>, pad_attribute = NO_PAD}
Protocol_classic::start_result_metadata会生成查询结果的元数据。
bool Protocol_classic::start_result_metadata(uint num_cols_arg, uint flags,
                                             const CHARSET_INFO *cs) {
  DBUG_TRACE;
  DBUG_PRINT("info", ("num_cols %u, flags %u", num_cols_arg, flags));
  uint num_cols = num_cols_arg;
  result_cs = cs;
  send_metadata = true;
  field_count = num_cols;
  sending_flags = flags;
..
  /*
    We don't send number of column for PS, as it's sent in a preceding packet.
  */
  if (flags & Protocol::SEND_NUM_ROWS) {
    uchar tmp[sizeof(ulonglong) + 1];
    uchar *pos = net_store_length((uchar *)&tmp, num_cols);

    if (has_client_capability(CLIENT_OPTIONAL_RESULTSET_METADATA)) {
      /* Store resultset metadata flag. */
      *pos = static_cast<uchar>(m_thd->variables.resultset_metadata);
      pos++;
    }

    my_net_write(&m_thd->net, (uchar *)&tmp, (size_t)(pos - (uchar *)&tmp));
  }
..
  /*
    field_types will be filled only if we send metadata.
    Set it to NULL if we skip resultset metadata to avoid
    ::storeXXX() method's asserts failures.
  */
  if (m_thd->variables.resultset_metadata == RESULTSET_METADATA_FULL)
    field_types =
        (enum_field_types *)m_thd->alloc(sizeof(field_types) * num_cols);
  else
    field_types = nullptr;
..

查看执行路径。

语句在解析、查询后,最后会进行查询结果的处理。

(gdb) backtrace
#0  Protocol_classic::start_result_metadata (this=0x7f542c0508b0, num_cols_arg=1, flags=5, 
    cs=0x8a09400 <my_charset_utf8mb4_0900_ai_ci>) at /data/mysql-8.0.42/sql/protocol_classic.cc:3081
#1  0x000000000352fd4f in THD::send_result_metadata (this=0x7f542c19a5a0, list=..., flags=5)
    at /data/mysql-8.0.42/sql/sql_class.cc:2851
#2  0x0000000003ce7929 in Query_result_send::send_result_set_metadata (this=0x7f542c1b0070, thd=0x7f542c19a5a0, 
    list=..., flags=5) at /data/mysql-8.0.42/sql/query_result.cc:71
#3  0x000000000375ef48 in Query_expression::ExecuteIteratorQuery (this=0x7f542c0d48c0, thd=0x7f542c19a5a0)
    at /data/mysql-8.0.42/sql/sql_union.cc:1703
#4  0x000000000375f610 in Query_expression::execute (this=0x7f542c0d48c0, thd=0x7f542c19a5a0)
    at /data/mysql-8.0.42/sql/sql_union.cc:1836
#5  0x00000000036ac5ec in Sql_cmd_dml::execute_inner (this=0x7f542c1b0038, thd=0x7f542c19a5a0)
    at /data/mysql-8.0.42/sql/sql_select.cc:1014
#6  0x00000000036aba23 in Sql_cmd_dml::execute (this=0x7f542c1b0038, thd=0x7f542c19a5a0)
    at /data/mysql-8.0.42/sql/sql_select.cc:785
#7  0x00000000036266d2 in mysql_execute_command (thd=0x7f542c19a5a0, first_level=true)
    at /data/mysql-8.0.42/sql/sql_parse.cc:4724
#8  0x0000000003628aae in dispatch_sql_command (thd=0x7f542c19a5a0, parser_state=0x7f54a4164970)
    at /data/mysql-8.0.42/sql/sql_parse.cc:5385
#9  0x000000000361e683 in dispatch_command (thd=0x7f542c19a5a0, com_data=0x7f54a4165a60, command=COM_QUERY)
    at /data/mysql-8.0.42/sql/sql_parse.cc:2055
#10 0x000000000361c5ca in do_command (thd=0x7f542c19a5a0) at /data/mysql-8.0.42/sql/sql_parse.cc:1440
#11 0x0000000003844598 in handle_connection (arg=0xc448c60)
    at /data/mysql-8.0.42/sql/conn_handler/connection_handler_per_thread.cc:303
#12 0x00000000058bf53d in pfs_spawn_thread (arg=0xc430ac0) at /data/mysql-8.0.42/storage/perfschema/pfs.cc:3050
#13 0x00007f54cde821ca in start_thread (arg=<optimized out>) at pthread_create.c:479
#14 0x00007f54cc3a18d3 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

接着调试后续的代码。

(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 7, Protocol_classic::store_string (this=0x7f542c0508b0, from=0x6774d37 "def", 
    length=3, fromcs=0x8a26400 <my_charset_utf8mb3_general_ci>) at /data/mysql-8.0.42/sql/protocol_classic.cc:3425
3425	  assert(send_metadata || field_types == nullptr ||
(gdb) backtrace
#0  Protocol_classic::store_string (this=0x7f542c0508b0, from=0x6774d37 "def", length=3, 
    fromcs=0x8a26400 <my_charset_utf8mb3_general_ci>) at /data/mysql-8.0.42/sql/protocol_classic.cc:3425
#1  0x0000000003ce47d3 in Protocol_classic::send_field_metadata (this=0x7f542c0508b0, field=0x7f54a4162b80, 
    item_charset=0x8a26400 <my_charset_utf8mb3_general_ci>) at /data/mysql-8.0.42/sql/protocol_classic.cc:3282
#2  0x000000000352fe82 in THD::send_result_metadata (this=0x7f542c19a5a0, list=..., flags=5)
    at /data/mysql-8.0.42/sql/sql_class.cc:2861
#3  0x0000000003ce7929 in Query_result_send::send_result_set_metadata (this=0x7f542c1b0070, thd=0x7f542c19a5a0, 
    list=..., flags=5) at /data/mysql-8.0.42/sql/query_result.cc:71
#4  0x000000000375ef48 in Query_expression::ExecuteIteratorQuery (this=0x7f542c0d48c0, thd=0x7f542c19a5a0)
    at /data/mysql-8.0.42/sql/sql_union.cc:1703
#5  0x000000000375f610 in Query_expression::execute (this=0x7f542c0d48c0, thd=0x7f542c19a5a0)
    at /data/mysql-8.0.42/sql/sql_union.cc:1836
#6  0x00000000036ac5ec in Sql_cmd_dml::execute_inner (this=0x7f542c1b0038, thd=0x7f542c19a5a0)
    at /data/mysql-8.0.42/sql/sql_select.cc:1014
#7  0x00000000036aba23 in Sql_cmd_dml::execute (this=0x7f542c1b0038, thd=0x7f542c19a5a0)
    at /data/mysql-8.0.42/sql/sql_select.cc:785
#8  0x00000000036266d2 in mysql_execute_command (thd=0x7f542c19a5a0, first_level=true)
    at /data/mysql-8.0.42/sql/sql_parse.cc:4724
#9  0x0000000003628aae in dispatch_sql_command (thd=0x7f542c19a5a0, parser_state=0x7f54a4164970)
    at /data/mysql-8.0.42/sql/sql_parse.cc:5385
#10 0x000000000361e683 in dispatch_command (thd=0x7f542c19a5a0, com_data=0x7f54a4165a60, command=COM_QUERY)
    at /data/mysql-8.0.42/sql/sql_parse.cc:2055
#11 0x000000000361c5ca in do_command (thd=0x7f542c19a5a0) at /data/mysql-8.0.42/sql/sql_parse.cc:1440
#12 0x0000000003844598 in handle_connection (arg=0xc448c60)
    at /data/mysql-8.0.42/sql/conn_handler/connection_handler_per_thread.cc:303
#13 0x00000000058bf53d in pfs_spawn_thread (arg=0xc430ac0) at /data/mysql-8.0.42/storage/perfschema/pfs.cc:3050
#14 0x00007f54cde821ca in start_thread (arg=<optimized out>) at pthread_create.c:479
#15 0x00007f54cc3a18d3 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb) info local
__PRETTY_FUNCTION__ = "virtual bool Protocol_classic::store_string(const char*, size_t, const CHARSET_INFO*)"
(gdb) info args
this = 0x7f542c0508b0
from = 0x6774d37 "def"
length = 3
fromcs = 0x8a26400 <my_charset_utf8mb3_general_ci>
(gdb) print *from
$40 = 100 'd'
Protocol_classic::store_string这个函数主要用于将字符串数据存储到网络协议包中,以便发送给客户端。
bool Protocol_classic::store_string(const char *from, size_t length,
                                    const CHARSET_INFO *fromcs) {
  // field_types check is needed because of the embedded protocol
  assert(send_metadata || field_types == nullptr ||
         field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
         field_types[field_pos] == MYSQL_TYPE_BIT ||
         field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL ||
         field_types[field_pos] == MYSQL_TYPE_NEWDATE ||
         field_types[field_pos] == MYSQL_TYPE_JSON ||
         (field_types[field_pos] >= MYSQL_TYPE_ENUM &&
          field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
  field_pos++;
  // result_cs is nullptr when client issues SET character_set_results=NULL
  if (result_cs != nullptr && !my_charset_same(fromcs, result_cs) &&
      fromcs != &my_charset_bin && result_cs != &my_charset_bin) {
    // Store with conversion.
    return net_store_data_with_conversion(pointer_cast<const uchar *>(from),
                                          length, fromcs, result_cs);
  }
  // Store without conversion.
  return net_store_data(pointer_cast<const uchar *>(from), length, packet);
}

继续后续的调试。

(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 7, Protocol_classic::store_string (this=0x7f542c0508b0, from=0x66e83d0 "", 
    length=0, fromcs=0x8a26400 <my_charset_utf8mb3_general_ci>) at /data/mysql-8.0.42/sql/protocol_classic.cc:3425
3425	  assert(send_metadata || field_types == nullptr ||
(gdb) print from
$41 = 0x66e83d0 ""
(gdb) print *from
$42 = 0 '\000'
(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 7, Protocol_classic::store_string (this=0x7f542c0508b0, from=0x66e83d0 "", 
    length=0, fromcs=0x8a26400 <my_charset_utf8mb3_general_ci>) at /data/mysql-8.0.42/sql/protocol_classic.cc:3425
3425	  assert(send_metadata || field_types == nullptr ||
(gdb) print *from
$43 = 0 '\000'
(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 7, Protocol_classic::store_string (this=0x7f542c0508b0, from=0x66e83d0 "", 
    length=0, fromcs=0x8a26400 <my_charset_utf8mb3_general_ci>) at /data/mysql-8.0.42/sql/protocol_classic.cc:3425
3425	  assert(send_metadata || field_types == nullptr ||
(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 7, Protocol_classic::store_string (this=0x7f542c0508b0, 
    from=0x7f542c0d5c70 "@@version_comment", length=17, fromcs=0x8a26400 <my_charset_utf8mb3_general_ci>)
    at /data/mysql-8.0.42/sql/protocol_classic.cc:3425
3425	  assert(send_metadata || field_types == nullptr ||
(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 7, Protocol_classic::store_string (this=0x7f542c0508b0, from=0x66e83d0 "", 
    length=0, fromcs=0x8a26400 <my_charset_utf8mb3_general_ci>) at /data/mysql-8.0.42/sql/protocol_classic.cc:3425
3425	  assert(send_metadata || field_types == nullptr ||
(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 8, THD::send_result_set_row (this=0x7f542c19a5a0, row_items=...)
    at /data/mysql-8.0.42/sql/sql_class.cc:2887
2887	  String str_buffer(buffer, sizeof(buffer), &my_charset_bin);

(gdb) info local
buffer = "\340f\000,T\177\000\000\000\000\000\000\000\000\000\000P,\026\244T\177\000\000 \000\000\000\000\000\000\000\000\224\240\b", '\000' <repeats 12 times>, "P,\026\244T\177\000\000\263\372\310\004\000\000\000\000P0\026\244T\177\000\000\300\026\313\b\000\000\000\000p,\026\244T\177\000\000\253\374\310\004\000\000\000\000\270\272\000,T\177\000\000\340f\000,T\177\000\000\240.\026\244T\177\000\000/(\311\004\000\000\000\000\000/\026\244T\177\000\000\001\000\000\000\000\000\000\000\260,\026\244T\177\000\000\263\372\310\004\000\000\000\000\300,\026\244T\177\000\000\300\026\313\b\000\000\000\000\320,\026\244T\177\000\000\253\374\310\004\000\000\000\000\270\272\000,T\177\000\000"...
str_buffer = {m_ptr = 0x88b7280 <my_charset_bin> "?", m_length = 766, m_charset = 0x7f54a4162c10, 
  m_alloced_length = 80280243, m_is_alloced = false}
_db_trace = {m_stack_frame = {func = 0x21 <error: Cannot access memory at address 0x21>, func_len = 31, 
    file = 0x7f54a4162b00 "@+\026\244T\177", level = 739068392, prev = 0x7f54a4162bf0}}
__PRETTY_FUNCTION__ = "bool THD::send_result_set_row(const mem_root_deque<Item*>&)"
(gdb) info args
this = 0x7f542c19a5a0
row_items = @0x7f542c0d49e8: {static block_elements = <optimized out>, m_blocks = 0x7f542c0d5ca8, m_begin_idx = 64, 
  m_end_idx = 65, m_capacity = 128, m_root = 0x7f542c19ced0, m_generation = 2}
(gdb) print row_items
$44 = (const mem_root_deque<Item*> &) @0x7f542c0d49e8: {static block_elements = <optimized out>, 
  m_blocks = 0x7f542c0d5ca8, m_begin_idx = 64, m_end_idx = 65, m_capacity = 128, m_root = 0x7f542c19ced0, 
  m_generation = 2}
(gdb) print row_items->m_root
$45 = (MEM_ROOT *) 0x7f542c19ced0
(gdb) print *row_items->m_root
$46 = {static s_dummy_target = 0 '\000', m_current_block = 0x7f542c1aeeb0, 
  m_current_free_start = 0x7f542c1b0aa8 '\217' <repeats 200 times>..., 
  m_current_free_end = 0x7f542c1b0ec0 "\217\217\217\217\217\217\217\217\361\037", m_block_size = 12288, 
  m_orig_block_size = 8192, m_max_capacity = 0, m_allocated_size = 16384, m_error_for_capacity_exceeded = false, 
  m_error_handler = 0x34f935d <sql_alloc_error_handler()>, m_psi_key = 9}
THD::send_result_set_row负责将查询结果的一行数据发送给客户端。
bool THD::send_result_set_row(const mem_root_deque<Item *> &row_items) {
  char buffer[MAX_FIELD_WIDTH];
  String str_buffer(buffer, sizeof(buffer), &my_charset_bin);

  DBUG_TRACE;
  DBUG_EXECUTE_IF("assert_only_current_thd_protocol_access",
                  { assert(current_thd == this); });

  for (Item *item : VisibleFields(row_items)) {
    if (item->send(m_protocol, &str_buffer) || is_error()) return true;
    /*
      Reset str_buffer to its original state, as it may have been altered in
      Item::send().
    */
    str_buffer.set(buffer, sizeof(buffer), &my_charset_bin);
  }
  return false;
}

继续调试后续的代码。

(gdb) c
Continuing.

Thread 36 "connection" hit Breakpoint 9, Item::send (this=0x7f542c0d59a8, protocol=0x7f542c0508b0, buffer=0x7f54a4162be0)
    at /data/mysql-8.0.42/sql/item.cc:7350
7350	  switch (data_type()) {
(gdb) info local
__PRETTY_FUNCTION__ = "virtual bool Item::send(Protocol*, String*)"
(gdb) info args
this = 0x7f542c0d59a8
protocol = 0x7f542c0508b0
buffer = 0x7f54a4162be0
(gdb) print *protocol
$47 = {_vptr.Protocol = 0x87d3238 <vtable for Protocol_text+16>, m_previous_protocol = 0x0}

(gdb) print *buffer
$48 = {m_ptr = 0x7f54a4162c00 "\340f", m_length = 766, m_charset = 0x88b7280 <my_charset_bin>, m_alloced_length = 766, 
  m_is_alloced = false}
(gdb) backtrace
#0  Item::send (this=0x7f542c0d59a8, protocol=0x7f542c0508b0, buffer=0x7f54a4162be0)
    at /data/mysql-8.0.42/sql/item.cc:7350
#1  0x0000000003530136 in THD::send_result_set_row (this=0x7f542c19a5a0, row_items=...)
    at /data/mysql-8.0.42/sql/sql_class.cc:2894
#2  0x0000000003ce7a1e in Query_result_send::send_data (this=0x7f542c1b0070, thd=0x7f542c19a5a0, items=...)
    at /data/mysql-8.0.42/sql/query_result.cc:101
#3  0x000000000375f3c2 in Query_expression::ExecuteIteratorQuery (this=0x7f542c0d48c0, thd=0x7f542c19a5a0)
    at /data/mysql-8.0.42/sql/sql_union.cc:1798
#4  0x000000000375f610 in Query_expression::execute (this=0x7f542c0d48c0, thd=0x7f542c19a5a0)
    at /data/mysql-8.0.42/sql/sql_union.cc:1836
#5  0x00000000036ac5ec in Sql_cmd_dml::execute_inner (this=0x7f542c1b0038, thd=0x7f542c19a5a0)
    at /data/mysql-8.0.42/sql/sql_select.cc:1014
#6  0x00000000036aba23 in Sql_cmd_dml::execute (this=0x7f542c1b0038, thd=0x7f542c19a5a0)
    at /data/mysql-8.0.42/sql/sql_select.cc:785
#7  0x00000000036266d2 in mysql_execute_command (thd=0x7f542c19a5a0, first_level=true)
    at /data/mysql-8.0.42/sql/sql_parse.cc:4724
#8  0x0000000003628aae in dispatch_sql_command (thd=0x7f542c19a5a0, parser_state=0x7f54a4164970)
    at /data/mysql-8.0.42/sql/sql_parse.cc:5385
#9  0x000000000361e683 in dispatch_command (thd=0x7f542c19a5a0, com_data=0x7f54a4165a60, command=COM_QUERY)
    at /data/mysql-8.0.42/sql/sql_parse.cc:2055
#10 0x000000000361c5ca in do_command (thd=0x7f542c19a5a0) at /data/mysql-8.0.42/sql/sql_parse.cc:1440
#11 0x0000000003844598 in handle_connection (arg=0xc448c60)
    at /data/mysql-8.0.42/sql/conn_handler/connection_handler_per_thread.cc:303
#12 0x00000000058bf53d in pfs_spawn_thread (arg=0xc430ac0) at /data/mysql-8.0.42/storage/perfschema/pfs.cc:3050
#13 0x00007f54cde821ca in start_thread (arg=<optimized out>) at pthread_create.c:479
#14 0x00007f54cc3a18d3 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Item::send负责将 Item 对象的数据发送到客户端。

/**
  This is only called from items that is not of type item_field.
*/

bool Item::send(Protocol *protocol, String *buffer) {
  switch (data_type()) {
    default:
    case MYSQL_TYPE_NULL:
    case MYSQL_TYPE_BOOL:
    case MYSQL_TYPE_INVALID:
    case MYSQL_TYPE_DECIMAL:
    case MYSQL_TYPE_ENUM:
    case MYSQL_TYPE_SET:
    case MYSQL_TYPE_TINY_BLOB:
    case MYSQL_TYPE_MEDIUM_BLOB:
    case MYSQL_TYPE_LONG_BLOB:
    case MYSQL_TYPE_BLOB:
    case MYSQL_TYPE_GEOMETRY:
    case MYSQL_TYPE_STRING:
    case MYSQL_TYPE_VAR_STRING:
    case MYSQL_TYPE_VARCHAR:
    case MYSQL_TYPE_BIT:
    case MYSQL_TYPE_NEWDECIMAL:
    case MYSQL_TYPE_JSON: {
      const String *res = val_str(buffer);
      assert(null_value == (res == nullptr));
      if (res != nullptr)
        return protocol->store_string(res->ptr(), res->length(),
                                      res->charset());
      break;
    }
..

Item::send函数会返回protocol->store_string函数。

(gdb) n
7369	      const String *res = val_str(buffer);
(gdb) n
7370	      assert(null_value == (res == nullptr));
(gdb) n
7371	      if (res != nullptr)
(gdb) n
7372	        return protocol->store_string(res->ptr(), res->length(),
(gdb) n

Thread 36 "connection" hit Breakpoint 7, Protocol_classic::store_string (this=0x7f542c0508b0, 
    from=0x7f542c1a3e70 "MySQL 8.0.42 test environment", length=29, fromcs=0x8a26400 <my_charset_utf8mb3_general_ci>)
    at /data/mysql-8.0.42/sql/protocol_classic.cc:3425
3425	  assert(send_metadata || field_types == nullptr ||

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值