共计 5246 个字符,预计需要花费 14 分钟才能阅读完成。
- 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::execute
Sql_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 公布!