• GreatSQL社区原创内容未经受权不得随便应用,转载请分割小编并注明起源。

导语

SHOW CREATE TABLE语句用于为指定表/视图显示创立的语句,本文将简要形容如何在MySQL源码里跟踪和学习此类语句的执行流程。 (注:应用版本为Percona-Server-8.0.25-15)

步骤

筹备工作

编译调试版本的 mysql server 程序,创立数据库实例后建设一张示例表:

create table t1(c1 int);

有了示例表, 在客户端执行如下语句,就能够在服务端开始咱们的语句跟踪了:

show create table t1;
断点设置

在如下函数/办法中设置断点(gdb):

dispatch_sql_command   # 对sql语句做词法/语法解析,失去理论要运行的sql命令mysql_execute_command  # 依据lex->sql_command值调用对应办法执行查问操作Sql_cmd_show_noplan::executeSql_cmd_show_create_table::execute_inner  # '执行'show create table指令mysqld_show_create  # 由Sql_cmd_show_create_table::execute_inner调用,获取表创立信息store_create_info   # 依据表属性拼接建表字串
代码跟踪与浏览

通过断点查看上下文代码,通过打印变量信息等伎俩,可大抵理解show create table t1的执行流程,以下列出几个执行中较要害的地位,并对源码内容做注解阐明:

  • 断点地位1: Sql_cmd_show_create_table::execute_inner(THD *) sql_show.cc:408

代码上下文:

bool Sql_cmd_show_create_table::execute_inner(THD *thd) {  // ... ... 注:为显示和阐明不便,局部代码已被省略,可自行参阅源码读取更全面信息  // 将指定表退出至session的table list,并初始化表的锁信息;相当于让session晓得,本次查问  // 将会用到这张表。  if (lex->query_block->add_table_to_list(thd, m_table_ident, nullptr, 0) ==      nullptr)    return true;  TABLE_LIST *tbl = lex->query_tables;  // ... ...  if (mysqld_show_create(thd, tbl)) return true;  //断点地位  return false;}
  • 断点地位2:mysqld_show_create(THD *, TABLE_LIST *) sql_show.cc:1206

代码上下文:

bool mysqld_show_create(THD *thd, TABLE_LIST *table_list) {  // ... ...  // 关上指定表/视图,获取显示数据信息所需的元数据锁(MDL)  bool open_error = open_tables(thd, &table_list, &counter,                                  MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL);  // 'show create table'语句也能够显示view的创立信息,本办法依据对应table element  // 的属性来确定调用view_store_create_info()还是store_create_info().  if (table_list->is_view())    view_store_create_info(thd, table_list, &buffer);  else if (store_create_info(thd, table_list, &buffer, nullptr, false)) //断点地位    goto exit;  // 获取到表/视图创立信息后,本办法还会组一张虚构表返回给客户端,客户端依据失去的表头和  // 数据内容,实现信息的展现,其后果示例如:  // +-------+----------------------------+  // | Table | Create Table               |  // +-------+----------------------------+  // | t1    | CREATE TABLE `t1` `c1` ... |  // +-------+----------------------------+  if (table_list->is_view()) {    field_list.push_back(new Item_empty_string("View", NAME_CHAR_LEN));    field_list.push_back(new Item_empty_string(        "Create View", max<uint>(buffer.length(), 1024U)));    field_list.push_back(        new Item_empty_string("character_set_client", MY_CS_NAME_SIZE));    field_list.push_back(        new Item_empty_string("collation_connection", MY_CS_NAME_SIZE));  } else {    field_list.push_back(new Item_empty_string("Table", NAME_CHAR_LEN));    // 1024 is for not to confuse old clients    field_list.push_back(new Item_empty_string(        "Create Table", max<size_t>(buffer.length(), 1024U)));  }  // ... ... }
  • 断点地位3: store_create_info(THD *, ...) sql_show.cc:1885

代码上下文:

bool store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,                       HA_CREATE_INFO *create_info_arg, bool show_database) {  // ... ...  // 依据指定表的属性,确定创立语句  if (share->tmp_table)    packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE "));  else    packet->append(STRING_WITH_LEN("CREATE TABLE "));  if (create_info_arg &&      (create_info_arg->options & HA_LEX_CREATE_IF_NOT_EXISTS))    packet->append(STRING_WITH_LEN("IF NOT EXISTS "));  if (table_list->schema_table)    alias = table_list->schema_table->table_name;  else {    if (lower_case_table_names == 2)      alias = table->alias;    else {      alias = share->table_name.str;    }  }  // ... ...  // 表的列信息生成  for (ptr = table->field; (field = *ptr); ptr++) {    // ... ...    if (ptr != table->field) packet->append(STRING_WITH_LEN(",\n"));    packet->append(STRING_WITH_LEN("  "));    append_identifier(thd, packet, field->field_name,                      strlen(field->field_name));    packet->append(' ');    // check for surprises from the previous call to Field::sql_type()    if (type.ptr() != tmp)      type.set(tmp, sizeof(tmp), system_charset_info);    else      type.set_charset(system_charset_info);  // ... ...}

store_create_info() 是一个比拟'大支'的代码(600+行), 其原理实质上就是遍历和指定表相干的所有属性,并一一将对应的创立信息塞入到当时预调配的String buffer里。

因为表的属性信息是在调用store_create_info前实时获取的,所以如果在咱们创立原始表后对表属性和构造做了变更,在show create table时,是能看到信息的变动的,以本文示例t1为例,咱们对其做如下操作:

create index idx_c1 on t1(idx);alter table t1 add column c2 int;

通过show create table t1,是可能看到前后显示信息的不同的。

原始表输入信息:

> show create table t1;+-------+----------------------------------------------------------+| Table | Create Table                                             |+-------+----------------------------------------------------------+| t1    | CREATE TABLE `t1` (                                      |`c1` int DEFAULT NULL                                              |        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |+-------+----------------------------------------------------------+1 row in set (1 hour 25 min 45.87 sec)

批改表后输入信息

> show create table t1;+-------+----------------------------------------------------------+| Table | Create Table                                             |+-------+----------------------------------------------------------+| t1    | CREATE TABLE `t1` (                                      |`c1` int DEFAULT NULL,                                             |       `c2` int DEFAULT NULL,                                             |KEY `idx_c1` (`c1`)                                                |) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |+-------+----------------------------------------------------------+1 row in set (0.00 sec)
结语

本文简要介绍了如何通过源码对MySQL show create table语句的执行流程进行学习和跟踪,
对其余 show 类型的语句如show create database,show create view,show create index等,具备不错的参考作用,有趣味的敌人亦可做尝试和摸索 :)

Enjoy GreatSQL :)

文章举荐:

面向金融级利用的GreatSQL正式开源
https://mp.weixin.qq.com/s/cI...

Changes in GreatSQL 8.0.25 (2021-8-18)
https://mp.weixin.qq.com/s/qc...

MGR及GreatSQL资源汇总
https://mp.weixin.qq.com/s/qX...

GreatSQL MGR FAQ
https://mp.weixin.qq.com/s/J6...

在Linux下源码编译装置GreatSQL/MySQL
https://mp.weixin.qq.com/s/WZ...

# 对于 GreatSQL

GreatSQL是由万里数据库保护的MySQL分支,专一于晋升MGR可靠性及性能,反对InnoDB并行查问个性,是实用于金融级利用的MySQL分支版本。

Gitee:

https://gitee.com/GreatSQL/Gr...

GitHub:

https://github.com/GreatSQL/G...

Bilibili:

https://space.bilibili.com/13...

微信&QQ群:

可搜寻增加GreatSQL社区助手微信好友,发送验证信息“加群”退出GreatSQL/MGR交换微信群

QQ群:533341697

微信小助手:wanlidbc

本文由博客一文多发平台 OpenWrite 公布!