本节,我们将讲述简单的 INSERT 语句是如何运行的。
create table t(id int primary key, val int);
insert into t values(1, 1), (10, 10), (100, 100); -- simple insert
insert into t(id, val) select id + 1, val + 1 from t; -- insert from select这是一条 INSERT 语句,会通过 executor/insert.go 中的 InsertExec 来执行。
- 1.
executor/builder.go,executorBuilder.buildInsert函数会构造InsertExec,InsertExec的结构体定义中组合了InsertValues。在构造时,会通过InsertValues.initInsertColumns生成执行所需要涉及到的 Columns 信息。 - 2.
executor/insert.go,InsertExec.Open方法会被调用,有的 Insert 是根据 Select 的结果写入的(如上面的第二条 Insert),这种情况下 Insert 中嵌入了一条 Select 语句,InsertExec中也嵌入了一个SelectionExec,在Open的时候也需要通过SelectionExec.Open初始化SelectionExec。 - 3.
executor/insert.go,InsertExec.Next中对普通的 Insert 和根据 Select 的 Insert 会调用不同的函数。- 3.1
executor/insert.go,普通的 Insert 会使用insertRows函数进行处理(例子中第一条 Insert)。 - 3.2
executor/insert.go,根据 Select 的 Insert 会使用insertRowsFromSelect函数进行处理(例子中第二条 Insert)。
- 3.1
- 4.
executor/insert.go,insertRows和insertRowsFromSelect都会使用InsertExec.exec来处理实际写入的数据,InsertExec.exec中,每行数据都会使用被组合的InsertValues.addRecord进行写入。 - 5.
executor/insert_common.go,InsertValues.addRecord会将输入的一行数据通过table/tables/tables.go中的TableCommon.AddRecord函数写入到 membuffer 当中。
以上是写入的关键路径,这个调用链路中的关键函数也被移除了,你需要根据调用链路的描述进行填充。