create table t1(id int);
insert into t1 values(1)
略过建立连接,从 mysql_parse() 开始分析
进入 mysql_execute_command()
/* ...... */
case SQLCOM_INSERT:
{
/* 检查权限 */
if ((res= insert_precheck(thd, all_tables)))
break;
/* 执行insert */
res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
lex->update_list, lex->value_list,
lex->duplicates, lex->ignore);
/* 提交或者回滚事务 */
if (!res)
{
trans_commit_stmt(thd);
trans_commit(thd);
thd->trx_end_by_hint= TRUE;
}
else if (res)
{
trans_rollback_stmt(thd);
trans_rollback(thd);
thd->trx_end_by_hint= TRUE;
}
bool mysql_insert(THD *thd,TABLE_LIST *table_list,
List<Item> &fields, /* insert 的字段 */
List<List_item> &values_list, /* insert 的值 */
List<Item> &update_fields,
List<Item> &update_values,
enum_duplicates duplic,
bool ignore)
{
/*对每条记录调用 write_record */
while ((values= its++))
{
if (lock_type == TL_WRITE_DELAYED)
{
LEX_STRING const st_query = { query, thd->query_length() };
DEBUG_SYNC(thd, "before_write_delayed");
/* insert delay */
error= write_delayed(thd, table, st_query, log_on, &info);
DEBUG_SYNC(thd, "after_write_delayed");
query=0;
}
else
/* normal insert */
error= write_record(thd, table, &info, &update);
}
/*
这里还有
thd->binlog_query()写binlog
my_ok()返回ok报文,ok报文中包含影响行数
*/
进入 write_record
/*
COPY_INFO *info 用来处理唯一键冲突,记录影响行数
COPY_INFO *update 处理 INSERT ON DUPLICATE KEY UPDATE 相关信息
*/
{
if (duplicate_handling == DUP_REPLACE || duplicate_handling == DUP_UPDATE)
{
/* 处理 INSERT ON DUPLICATE KEY UPDATE 等复杂情况 */
}
/* 调用存储引擎的接口 */
else if ((error=table->file->ha_write_row(table->record[0])))
{
DEBUG_SYNC(thd, "write_row_noreplace");
if (!ignore_errors ||
table->file->is_fatal_error(error, HA_CHECK_DUP))
goto err;
table->file->restore_auto_increment(prev_insert_id);
goto ok_or_after_trg_err;
}
}
进入ha_write_row、write_row
进入引擎层,这里是innodb引擎,handler对应ha_innobase 插入的表信息保存在handler中
int
ha_innobase::write_row(
/*===================*/
uchar* record) /*!< in: a row in MySQL format */
{
error = row_insert_for_mysql((byte*) record, prebuilt);
}
UNIV_INTERN
dberr_t
row_insert_for_mysql(
/*=================*/
byte* mysql_rec, /*!< in: row in the MySQL format */
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
handle */
{
/*记录格式从MySQL转换成InnoDB*/
row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
thr->run_node = node;
thr->prev_node = node;
/*插入记录*/
row_ins_step(thr);
}
UNIV_INTERN
que_thr_t*
row_ins_step(
/*=========*/
que_thr_t* thr) /*!< in: query thread */
{
/*给表加IX锁*/
err = lock_table(0, node->table, LOCK_IX, thr);
/*插入记录*/
err = row_ins(node, thr);
}
InnoDB表是基于B+树的索引组织表
row_id分配逻辑在row_ins中,这里不详细展开
插入单个索引项
static __attribute__((nonnull, warn_unused_result))
dberr_t
row_ins_index_entry_step(
/*=====================*/
ins_node_t* node, /*!< in: row insert node */
que_thr_t* thr) /*!< in: query thread */
{
dberr_t err;
row_ins_index_entry_set_vals(node->index, node->entry, node->row);
/*插入索引项*/
err = row_ins_index_entry(node->index, node->entry, thr);
return(err);
}
static
dberr_t
row_ins_index_entry(
/*================*/
dict_index_t* index, /*!< in: index */
dtuple_t* entry, /*!< in/out: index entry to insert */
que_thr_t* thr) /*!< in: query thread */
{
if (dict_index_is_clust(index)) {
/* 插入聚集索引 */
return(row_ins_clust_index_entry(index, entry, thr, 0));
} else {
/* 插入二级索引 */
return(row_ins_sec_index_entry(index, entry, thr));
}
}
row_ins_clust_index_entry 和 row_ins_sec_index_entry 函数结构类似,只分析插入聚集索引
UNIV_INTERN
dberr_t
row_ins_clust_index_entry(
/*======================*/
dict_index_t* index, /*!< in: clustered index */
dtuple_t* entry, /*!< in/out: index entry to insert */
que_thr_t* thr, /*!< in: query thread */
ulint n_ext) /*!< in: number of externally stored columns */
{
if (UT_LIST_GET_FIRST(index->table->foreign_list)) {
err = row_ins_check_foreign_constraints(
index->table, index, entry, thr);
if (err != DB_SUCCESS) {
return(err);
}
}
/* flush log,make checkpoint(如果需要) */
log_free_check();
/* 先尝试乐观插入,修改叶子节点 BTR_MODIFY_LEAF */
err = row_ins_clust_index_entry_low(
0, BTR_MODIFY_LEAF, index, n_uniq, entry, n_ext, thr,
&page_no, &modify_clock);
if (err != DB_FAIL) {
DEBUG_SYNC_C("row_ins_clust_index_entry_leaf_after");
return(err);
}
/* flush log,make checkpoint(如果需要) */
log_free_check();
/* 乐观插入失败,尝试悲观插入 BTR_MODIFY_TREE */
return(row_ins_clust_index_entry_low(
0, BTR_MODIFY_TREE, index, n_uniq, entry, n_ext, thr,
&page_no, &modify_clock));
row_ins_clust_index_entry_low 和 row_ins_sec_index_entry_low 函数结构类似,只分析插入聚集索引