最近在mysql 8.0的代码上开发新的功能的时候,梳理了insert语句的执行过程,由于insert语句比较复杂并且涉及的内容很多,在下面准备分3章节来分析,这是第一个章节,主要讲述sql解析和命令的分发部分。
代码版本:mysql 8.0.22
编程语言:c++ && c++11 && c++14 && c++17
SQL语句是:
create table test(c1 int primary key, c2 varchar(50))engine=innodb;
insert into test values(1,"abc");
源码开始位置在/sql/sql_parse.h 和 /sql/sql_parse.cc,sql_parse.cc是一个超大的文件,里面包括了很多个超大的函数,下面按sql执行顺序讲述:
| > do_command
| | > dispatch_command
| | | > mysql_parse(parse_sql)
| | | | > mysql_execute_command --> lex->m_sql_cmd->execute(thd)
| | | | | > thd->send_statement_status() // 检查当前sql的状态
1、do_command:从客户端connection到mysql server之后,接收到sql命令的入口
bool do_command(THD *thd) {
bool return_value;
int rc;
NET *net = nullptr;
enum enum_server_command command;
COM_DATA com_data;
DBUG_TRACE;
DBUG_ASSERT(thd->is_classic_protocol());
/*
indicator of uninitialized lex => normal flow of errors handling
(see my_message_sql)
*/
thd->lex->set_current_select(nullptr);
/*
XXX: this code is here only to clear possible errors of init_connect.
Consider moving to prepare_new_connection_state() instead.
That requires making sure the DA is cleared before non-parsing statements
such as COM_QUIT.
*/
thd->clear_error(); // Clear error message
thd->get_stmt_da()->reset_diagnostics_area();
thd->updated_row_count = 0;
thd->busy_time = 0;
thd->cpu_time = 0;
thd->bytes_received = 0;
thd->bytes_sent = 0;
thd->binlog_bytes_written = 0;
...
...
return_value = dispatch_command(thd, &com_data, command);
thd->get_protocol_classic()->get_output_packet()->shrink(
thd->variables.net_buffer_length);
out:
/* The statement instrumentation must be closed in all cases. */
DBUG_ASSERT(thd->m_digest == nullptr);
DBUG_ASSERT(thd->m_statement_psi == nullptr);
return return_value;
}
2、dispatch_command: 按照不同的SQL进行分类
case COM_QUERY: {
DBUG_ASSERT(thd->m_digest == nullptr);
thd->m_digest = &thd->m_digest_state;
thd->m_digest->reset(thd->m_token_array, max_digest_length);
if (alloc_query(thd, com_data->com_query.query,
com_data->com_query.length))
break; // fatal error is set
const char *packet_end = thd->query().str + thd->query().length;
if (opt_general_log_raw)
query_logger.general_log_write(thd, command, thd->query().str,
thd->query().length);
DBUG_PRINT("query", ("%-.4096s", thd->query().str));
#if defined(ENABLED_PROFILING)
thd->profiling->set_query_source(thd->query().str, thd->query().length);
#endif
const LEX_CSTRING orig_query = thd->query();
Parser_state parser_state;
if (parser_state.init(thd, thd->query().str, thd->query().length)) break;
// Initially, prepare and optimize the statement for the primary
// storage engine. If an eligible secondary storage engine is
// found, the statement may be reprepared for the secondary
// storage engine later.
const auto saved_secondary_engine = thd->secondary_engine_optimization();
thd->set_secondary_engine_optimization(
Secondary_engine_optimization::PRIMARY_TENTATIVELY);
mysql_parse(thd, &parser_state, false);
...
...
3、mysql_parse(parse_sql):从文本字符串中解析输入的SQL,将解析出的AST树传给执行者
void mysql_parse(THD *thd, Parser_state *parser_state, bool update_userstat) {
DBUG_TRACE;
DBUG_PRINT("mysql_parse", ("query: '%s'", thd->query().str));
DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););
mysql_reset_thd_for_next_command(thd);
lex_start(thd);
bool err = thd->get_stmt_da()->is_error();
if (!err) {
err = parse_sql(thd, parser_state, nullptr);
...
...
error = mysql_execute_command(thd, true);
}
4、mysql_execute_command: 按照不同的SQL分类,进入不同的执行流程
switch (lex->sql_command) {
case SQLCOM_PREPARE: {
mysql_sql_stmt_prepare(thd);
break;
}
case SQLCOM_EXECUTE: {
mysql_sql_stmt_execute(thd);
break;
}
case SQLCOM_DEALLOCATE_PREPARE: {
mysql_sql_stmt_close(thd);
break;
}
...
...
case SQLCOM_REPLACE:
case SQLCOM_INSERT:
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
case SQLCOM_DELETE:
case SQLCOM_DELETE_MULTI:
case SQLCOM_UPDATE:
case SQLCOM_UPDATE_MULTI:
case SQLCOM_CREATE_TABLE:
case SQLCOM_CREATE_INDEX:
case SQLCOM_DROP_INDEX:
case SQLCOM_ASSIGN_TO_KEYCACHE:
case SQLCOM_PRELOAD_KEYS:
case SQLCOM_LOAD: {
DBUG_ASSERT(first_table == all_tables && first_table != nullptr);
DBUG_ASSERT(lex->m_sql_cmd != nullptr);
res = lex->m_sql_cmd->execute(thd);
break;
}
}
数据插入部分在sql/sql_insert.cc中,执行的顺序如下:
| > Sql_cmd_dml::execute
| | > write_record
1、Sql_cmd_dml::execute : 向一个表中插入一行或多行,执行一个DML语句,这里是insert into test values(1,"abc");
bool Sql_cmd_dml::execute(THD *thd) {
DBUG_TRACE;
// Perform statement-specific execution
if (execute_inner(thd)) goto err;
...
...
}
2、write_record : 在sql_insert.cc中,功能:向表中写入一条记录,可选择删除冲突的记录。
如果需要,调用适当的触发器,参数如下:
THD *thd : 当前thread的上下文 TABLE *table : 该条record要插入到的table COPY_INFO *info : 用来处理唯一键冲突,记录影响行数 COPY_INFO *update : 处理 INSERT ON DUPLICATE KEY UPDATE 相关信息
bool write_record(THD *thd, TABLE *table, COPY_INFO *info, COPY_INFO *update) {
...
store_record(table, insert_values);
...
}
这一章节主要讲述sql解析、命令的分发、进入innodb存储引擎之前的sql转换等。第二章节主要讲述sql命令传递给innodb之前的一些格式转换和初步的数据插入。
文章浏览阅读1.6w次,点赞8次,收藏41次。生活中我们无时不刻不都要在网站搜索资源,但就是缺少一个趁手的资源搜索网站,如果有一个比较好的资源搜索网站可以帮助我们节省一大半时间!今天小编在这里为大家分享5款超厉害的资源搜索网站,每一款都可以让你的资源丰富精彩!网盘传奇一款最有效的网盘资源搜索网站你还在为找网站里面的资源而烦恼找不到什么合适的工具而烦恼吗?这款网站传奇网站汇聚了4853w个资源,并且它每一天都会持续更新资源;..._最全资源搜索引擎
文章浏览阅读4.5k次,点赞5次,收藏18次。阅读测试程序,设计一个Book类。函数接口定义:class Book{}该类有 四个私有属性 分别是 书籍名称、 价格、 作者、 出版年份,以及相应的set 与get方法;该类有一个含有四个参数的构造方法,这四个参数依次是 书籍名称、 价格、 作者、 出版年份 。裁判测试程序样例:import java.util.*;public class Main { public static void main(String[] args) { List <Book>_6-1 book类的设计java
文章浏览阅读613次,点赞28次,收藏27次。相比于以前的传统手工管理方式,智能化的管理方式可以大幅降低学校的运营人员成本,实现了校园导航的标准化、制度化、程序化的管理,有效地防止了校园导航的随意管理,提高了信息的处理速度和精确度,能够及时、准确地查询和修正建筑速看等信息。课题主要采用微信小程序、SpringBoot架构技术,前端以小程序页面呈现给学生,结合后台java语言使页面更加完善,后台使用MySQL数据库进行数据存储。微信小程序主要包括学生信息、校园简介、建筑速看、系统信息等功能,从而实现智能化的管理方式,提高工作效率。
传统上用户登陆状态会以 Session 的形式保存在服务器上,而 Session ID 则保存在前端的 Cookie 中;而使用 JWT 以后,用户的认证信息将会以 Token 的形式保存在前端,服务器不需要保存任何的用户状态,这也就是为什么 JWT 被称为无状态登陆的原因,无状态登陆最大的优势就是完美支持分布式部署,可以使用一个 Token 发送给不同的服务器,而所有的服务器都会返回同样的结果。有状态和无状态最大的区别就是服务端会不会保存客户端的信息。
文章浏览阅读784次。发表于10小时前| 2674次阅读| 来源TechCrunch| 19 条评论| 作者Jon EvansiOSAndroid应用开发产品编程语言JavaObjective-C摘要:即便Android市场份额已经超过80%,对于开发者来说,使用哪一个平台做开发仍然很难选择。本文从开发环境、配置、UX设计、语言、API、网络、分享、碎片化、发布等九个方面把Android和iOS_ios 开发角度
搜索引擎的发展历史可以追溯到20世纪90年代初,随着互联网的快速发展和信息量的急剧增加,人们开始感受到了获取和管理信息的挑战。这些阶段展示了搜索引擎在技术和商业模式上的不断演进,以满足用户对信息获取的不断增长的需求。
文章浏览阅读990次。对象特性是指控制对象的输出参数和输入参数之间的相互作用规律。放大系数K描述控制对象特性的静态特性参数。它的意义是:输出量的变化量和输入量的变化量之比。时间常数T当输入量发生变化后,所引起输出量变化的快慢。(动态参数) ..._控制对象特性
文章浏览阅读5.7w次,点赞50次,收藏276次。FRP搭建内网穿透1.概述:frp可以通过有公网IP的的服务器将内网的主机暴露给互联网,从而实现通过外网能直接访问到内网主机;frp有服务端和客户端,服务端需要装在有公网ip的服务器上,客户端装在内网主机上。2.简单的图解:3.准备工作:1.一个域名(www.test.xyz)2.一台有公网IP的服务器(阿里云、腾讯云等都行)3.一台内网主机4.下载frp,选择适合的版本下载解压如下:我这里服务器端和客户端都放在了/usr/local/frp/目录下4.执行命令# 服务器端给执_locyanfrp
文章浏览阅读687次。题目:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=93745#problem/A题意:给出r*c的01矩阵,可以翻转格子使得0表成1,1变成0,求出最小的步数使得每一行中1的个数相等,每一列中1的个数相等。思路:网络流。容量可以保证每一行和每一列的1的个数相等,费用可以算出最小步数。行向列建边,如果该格子是_uva12534
文章浏览阅读504次。1、Let's Encrypt 90天,支持泛域名2、Buypass:https://www.buypass.com/ssl/resources/go-ssl-technical-specification6个月,单域名3、AlwaysOnSLL:https://alwaysonssl.com/ 1年,单域名 可参考蜗牛(wn789)4、TrustAsia5、Alpha..._csdn alphassl免费申请
文章浏览阅读1.6k次。测试算法的性能 很多时候我们需要对算法的性能进行测试,最简单的方式是看算法在特定的数据集上的执行时间,简单的测试算法性能的函数实现见testSort()。【思想】:用clock_t计算某排序算法所需的时间,(endTime - startTime)/ CLOCKS_PER_SEC来表示执行了多少秒。【关于宏CLOCKS_PER_SEC】:以下摘自百度百科,“CLOCKS_PE_算法性能测试
文章浏览阅读1.2k次。fromhttps://towardsdatascience.com/finding-lane-lines-simple-pipeline-for-lane-detection-d02b62e7572bIdentifying lanes of the road is very common task that human driver performs. This is important ..._lanedetectionlite